In this short article I’d like to explain how you can use the typeclass pattern in Scala to implement adhoc polymorphism. We won’t go into too much theoretical details in this article, the main thing I want to show you is how easy is really is to create a flexible extensible model without tying your domain model to specific implementation or traits. There are many resources regarding scala typeclasses available on the internet, but I couldn’t find a good reference, so that’s why I created this one. In this example we’ll look at a very pragmatic (and naive) implementation of the read typeclass from haskell. This type class allows you to convert a string to a specific type in a generic way.
What we want to accomplish with this typeclass is the following (The complete example can be found here: https://gist.github.com/josdirksen/9051baf09003dac37386)
With the Readable typeclass we provide a generic way to convert a String to a specific type. In the example above we used the type class to convert a String to some basic types, but also to different lists and a specific case class. The functionality for the basic types isn’t really that useful, since the scala String object already provides the toDouble, toString, etc. functions. This way, however, you don’t need to know the specific function to call, but you can just specify the target type you want :) It, however, gets much more interesting with the Task case class you see here. As you’ll see in the rest of the code, through the use of implicits we can simply add support for this case class, without having to change the implementation of either the String class or the Task class.
To implement a typeclass we first have to define the trait that defines the functions we need to implement. In this sample, we have only one function:
The read function should just transform the String to the specified type T. Now that we’ve defined our trait, lets look at the companion object, which contains some helper classes and simple implementations:
The code shouldn’t be that hard to understand. What we do here, is we create a number of Readable implementations. It’s important to note that we use the implicit parameter, so that we can pull them into scope later on. At this point we can already start using the typeclass. For that we import the implicits and use the Readable type class like this:
Easy right? Scala will look for an implicit that matches the specified type and convert the String to that type. This is nice, but doesn’t really look that nice. We need to instantiate a Readable (even though that isn’t too much code) and call read to convert the String. We can make it easier by extending the String class with a read function that does the conversion for us. For this add the following to the Readable companion object.
These operation define an implicit transformation which add the read function the String object. All that is left is to import the ops implicit functions and we can use the read directly:
This same approach can also be used to create a read function for case classes:
And that’s pretty much it. By just implementing the Readable[Task] trait our custom Task case class can be processed in the same manner as the other objects.