The aim of this short blog post is to give you enough information about type classes (in Scala) that you won’t twitch every time someone mentions the subject on twitter. It will focus on one application of type classes: An alternative to ad-hoc polymorphism. Once you have more time I’d suggest reading the paper Type Classes as Objects and Implicits to get a better understand of the subject.
The above article states that type classes have two roles
- Define a set of requirements for the type parameters used by generic algorithms
- Propagate constraints automatically making generic algorithms convenient and practical to use
The first is achieved by defining a trait and the second by providing an implicit object which extends that trait for a given type and an implicit parameter to the generic algorithm.
Now to make it a bit less abstract lets use an example. Assume you want to write a method named ‘greedy’ which picks the largest of whichever two instances of the same class you pass to the method. For this we need to have some idea of the ordering of the instances. Instead of forcing the instances to extend some type you can accomplish it with type classes.
case class MyModel(val data: Int)
trait Ord[T] {
def compare (x: T, y: T): Boolean
}
implicit object ordMyModel extends Ord[MyModel] {
def compare (m1: MyModel, m2: MyModel) = m1.data <= m2.data
}
def greedy[T](m1: T,m2: T)(implicit ordM: Ord[T]) =
if (ordM.compare (m1,m2)) m2 else m1
With the above code you can invoke the following in the REPL
val m1 = new MyModel(3) val m2 = new MyModel(5) greedy(m1,m2)
The nice thing about this is that if you want to be able to use the method greedy with another type you simply have to implement and implicit object which extends the Ord[T] trait. This keeps the inheritance chain of your classes clean.