Type Classes for ad-hoc Polymorphism in Scala

Amit Prasad
Analytics Vidhya
Published in
3 min readOct 5, 2021

Scala has a rich set of polymorphism techniques in order to achieve code reusability using traits, abstract classes, and of course, sometimes using case object and case classes.

Let’s consider we want to achieve the common functionality of equals (custom equals methods ) based on the type we operate on, that can be Int, Double, Person(case class), or any other types within scala ecosystems along with user-defined type as well.

One solution we can think of is to create the generics code block and operate on that but the problem here would be for each type we might end up having n numbers of object creation in order to achieve the functionality of equals method. We want to achieve something where only one object will be referred to operate on different types

The question here is how would we achieve this?

This is where type classes concept can rescue us and we often call it ad-hoc polymorphism

Now we can jump to solve the problem and below is the simple method where we would try to implement the isEqual method.

So now we are ready with the trait which holds the isEqual method for and we will see how further we can extend this to leverage the functionality of type-class and ad-hoc polymorphism.

But before that let me give a one-liner for implicit and this is a prerequisite to understanding this whole concept :

Implicits play a major role if you want the compiler to take the decision on your behalf to infer the values for the underlying execution of code blocks that are marked to use implicit.

Now let’s create a companion object for the above trait and use the implicit to instantiate the object for trait Equality[T].

If we see the above code snippet we can see in order to achieve the functionality of def isEqual[T]at line number 2 we are calling the passed value to the isEqual of the implicit object of equality (implicit equality:Equality[T] .

Now let’s see how we can use this companion object in order to override the isEqual methods for different types. First, we will see for Int

Alright, so we are extending and making use of implicit objects so that at runtime compiler will decide and choose the appropriate helper object to infer the actual implementation and so are we extending the Equality[Int] and the similar way we can do it for other types and implementation is completely independent of us.

So if we want to check for one user-defined type maybe User class we can do it in this way.

So above is the equal based on age only, and we can say the here we are only concerned on age equality.

So lots of discussion on the code but finally the question is which is the main object we should refer to call the isEqual and answer is Equality.isEqual(...)

So we if notice based on the type we are passing into isEqualof Equality the object is trying to find at run-time and execute the underlying logic and so is the reason 1,2 are going into IntEqualityand the second one is going into UseEqualilty block.

Hope this helps :)
Full code can be found here

--

--

Amit Prasad
Analytics Vidhya

Engineer by profession, Scala | Data engineering | Distributed System Linkedin: https://www.linkedin.com/in/amitprasad119/