Type classes in Scala

After a few months with the blog, we now know where we can use traits, what is the purpose of implicits, or what the hell are generic types. Today, we are going to use a little bit of everything in order to explain type classes.

In spite of their name, type classes are not related with the object-oriented programming paradigm, but with functional programming. By using this technique, we will be able to add ad hoc functionality to the types we want. This applies for both the primitive types of the language and the custom types that we may have created.

How are type classes implemented in Scala?

In order to illustrate the explanation, we are going to use a small example.
First, what we will do is to create a trait with the functionality that we want to add to the types. As we want it to be reusable by different types, the trait will be parameterized with the generic type T.

trait Addable[T] {
  def +(a: T, b: T): T
}

Now the trait is well-defined, let’s define implicit objects that inherit from it. We will have to create an object for each type that we want to have such functionality. Plus, we must implement in each object how the elements of that given type should be added.

object Addables {
  implicit object AddableLikeInt extends Addable[Int] {
    def +(a: Int, b: Int): Int = a + b
  }

  implicit object AddableLikeString extends Addable[String] {
    def +(a: String, b: String): String = a + b
  }

  implicit object AddableLikeBoolean extends Addable[Boolean] {
    def +(a: Boolean, b: Boolean): Boolean = a && b
  }
}

As can be seen, in this example we’re defining the method + for the Int, String and Boolean types. Now these types can make use of the addition functionality.

Mmmm… and how exactly can they be used?

We have already defined type classes for three primitive types. To give use to them, we will define a method called plus, which implements the addition of two elements of the same type.

def plus[T](a1: T, a2: T)(implicit ev: Addable[T]): T = ev.+(a1, a2)

In order to force the type of the elements that we want to add to be Addable, we will use in the method signature an implicit value of type Addable[T]. This way, the method will look for an object that extends the Addable[T] type in its scope,  where T is the type of the values we want to add. This implicit value is often referred to as evidence.
Well, let’s test it:

import Addables._  

plus(true, false) //false

As a reminder, let me mention that syntactic sugar can be applied and Context Bounds be used to mark these evidences:

def plus[T:Addable](a1: T, a2: T)

Awesome! But what happens if we want to add a type not previously defined? Then, we would get an error telling us that there isn’t any implicit object with that type in the scope:

plus(1.0, 2.0) // error: could not find implicit value for parameter ev: Addable[Double]

Fixing this is quite simple. We just have to create another implicit object with the desired type. In this case, with the Double type:

implicit object AddableLikeDouble extends Addable[Double] {
  def +(a: Double, b: Double): Double = a + b
}

plus(1.0, 2.0) //3.0

Now we can add two values of type Double. The same thing applies to types defined by ourselves:

case class Group(name: String, people: Set[String])

implicit object AddableLikeGroup extends Addable[Group] {
  def +(a: Group, b: Group): Group =
    Group(
      name = a.name + " & " + b.name,
      people = a.people | b.people
    )
}

Now Groups can be added too:

plus(Group("A", Set("Peter")), Group("B", Set("John, Chris"))) 
//Group("A & B", Set("Peter", "John", "Chris"))

Bonus

As we have seen, type classes allow us to extend functionality in a simple and elegant way. It can be applied to both primitives types, as well as our own user-defined types. In addition, by handling the scope of implicit objects, we have control over when we want a specific type to extend a given functionality.

This technique is perfect for us to explore more complex matters in depth in future posts. What we have seen today is the first step in understanding monoids, algebraic structures that can be found in functional libraries such as Scalaz or Cats. But this is all for now, I leave you yearning for more 🙂

Happy summer!

Un comentario en “Type classes in Scala

  1. […] We are like the fascicles of tin soldier collections and the free enrollment at gyms … back in September! And with something that seems a little harsh but that surely after reading a few lines will be easier. Today we initiate a series of posts in which we’ll discuss some functional abstractions, that are very related to the world of mathematics, with the aim of being gradually introduced into the world of purely functional Scala libraries, such as as Scalaz or Cats. To do this, we will rely on some features and techniques that have already been discussed, such as type classes. […]

    Me gusta

Deja un comentario