Implicit conversion is a very powerful feature provided by the Scala language. Its most common use case is to add capabilities to a class that is outside of the developer’s control (e.g. a third-party library), a pattern referred to as “Pimp my library”. Let’s look at a very basic example:

 1 // This is the class provided by the third party library, no way to change this code.
 2 class Person(val firstName: String, val lastName: String)
 3 
 4 // A wrapper for Person providing the much needed fullName field
 5 class RichPerson(person: Person){
 6   val fullName: String = person.firstName + " " + person.lastName
 7 }
 8 
 9 // The implicit conversion to go from a Person instance to a RichPerson
10 implicit def personToRichPerson(person: Person): RichPerson = 
11   new RichPerson(person)
12 
13 // Assuming that the implicit conversion is in scope, you can now write:
14 val p = new Person("Bob", "Saget")
15 println(p.fullName)

Most of the work happens at compile time: the compiler realizes that fullName does not exist in Person, it then searches the current scope for an implicit conversion from Person to [something that has a fullName field defined]. If no matching implicit conversion is available in scope you get a compilation error.

Scala 2.10 introduces a new syntax that makes it even easier to define implicit conversions thanks to implicit classes:

 1 // Still the class provided by the third party library
 2 class Person(val firstName: String, val lastName: String)
 3 
 4 // A wrapper for Person providing the much needed fullName method
 5 implicit class RichPerson(person: Person){
 6   val fullName: String = person.firstName + " " + person.lastName
 7 }
 8 
 9 val p = new Person("Bob", "Saget")
10 println(p.fullName)

Note that personToRichPerson is gone. By using the implicit keyword when defining our RichPerson wrapper we save ourselves the need to write the implicit conversion, the compiler will generate it for us.

Before Scala 2.10, implicit conversions came at a certain cost. The compiler has to look up the appropriate conversion, this takes time, but this look-up is done at compile time so not much of an issue. However, at runtime, the program still needs to instantiate an instance of RichPerson each time you want to access the fullName field (or any other field defined in your rich wrapper):

1 // What really happens when you invoke fullName on Person
2 val p = new Person("Bob", "Saget")
3 println(new RichPerson(p).fullName)

To solve this problem, Scala 2.10 includes a new feature called value classes designed to avoid the creation of instances at runtime. Let’s update our example to take advantage of this addition:

 1 // Still the class provided by the third party library
 2 class Person(val firstName: String, val lastName: String)
 3 
 4 // A wrapper for Person providing the much needed fullName method
 5 implicit class RichPerson(val person: Person) extends AnyVal {
 6   def fullName: String = person.firstName + " " + person.lastName
 7 }
 8 
 9 val p = new Person("Bob", "Saget")
10 println(p.fullName)

Quite a few changes here. Before looking at the code in details, what is happening now that our RichPerson is defined as a value class? The compiler silently creates a companion object for RichPerson with a method fullName(p: Person): String and each time our code calls fullName on a Person instance the compiler re-routes the call to use the static method, passing the Person instance as single argument. No more wrapper instance creation.

1 // The companion object generated by the compiler
2 object RichPerson {
3   def fullName(p: Person): String = 
4     person.firstName + " " + person.lastName
5 }
6 
7 // What happens when you call fullName on a Person instance
8 val p = new Person("Bob", "Saget")
9 println(RichPerson.fullName(p))

We can examine the changes we made to the code:

  • our class now extends AnyVal;
  • fullName is defined as a def instead of a val, this is because value classes can only have def members;
  • person in the constructor is defined as val, again, this is a requirement of value classes: the primary constructor can only take one parameter and it has to be a val.

Value classes come with other requirements not visible in our example, to name a few:

  • the class can only have one constructor, the primary constructor;
  • the single val parameter of the primary constructor cannot have a value class for type.

The combination of implicit classes and value classes provides scala developers with a very simple, concise and cheap mechanism to extend and enrich existing code and libraries.