Beside the fusion of object orientation and functional programming, I think that implicits – implicit classes, conversions, parameters and values – are Scala’s most intrinsic feature. They are a very powerful tool and therefore you should follow the Spider-Man principle: “with great power comes great responsibility”. But hey, they also say “no risk no fun”, so let’s fasten our seatbelts and start a discovery tour of implicitlandia.
Use case: type-safe equality
Our discovery tour will be centered around the use case of type-safe equality. In Java and – because of Java compatibility – also in Scala, equality is untyped:
1 2 3 4
As you can see,
equals takes an argument of type
Any. Therefore we can compare apples with pies, a
Person with an
Option[Person], etc. In most cases, this is not what we want, and this can lead to errors which are very hard to analyze. Instead, we’d like to have a type-safe equality operation like:
1 2 3
All right, what we need is a
=== method that can be called on objects of some type and takes another object of that particular type instead of
Any. In other words, we need a polymorphic method:
But there is no
Any or any of the other standard classes. And Scala doesn’t support extension methods, right? Well, not directly, but we can use implicits to achieve the same effect.
The basic idea is quite simple: Wrap an object that needs to be extended with one that provides the “extension method” and define an implicit conversion from the type that is to be extended to the wrapper. In our case the type to be extended is any type, so we have to provide a polymorphic conversion. Since Scala 2.10 these two steps can be unified by providing an implicit class:
1 2 3 4 5
As implicit classes are desugared into the wrapper class and the implicit conversion by the Scala compiler, they can’t be defined at the top-level. Therefore we define the implicit
Equal class inside of the
SimpleEquality singleton object. By importing
SimpleEquality._ we bring the implicit conversion into scope and can make use of our nice type-safe equality operation:
1 2 3 4 5 6 7 8 9 10 11 12 13
Nice, eh? Well, some of you might be concerned about the potential performance impact of creating wrapper objects at runtime. Fortunately Scala 2.10 offers value classes, which we can use to avoid this creation of the wrappers. All we have to do is extend from
AnyVal and make the wrapped value a
val. Then the Scala compiler will inline the “extension methods”. Here is the final state of our first and simple approach:
1 2 3 4 5
In this post we have discussed the problems with untyped equality and shown how to provide a simple type-safe equality operation using implicit classes. In the next post we’ll look at the drawbacks of our simple solution and provide a more sophisticated one which makes use of more implicit goodness.
The full source code is available on GitHub.