Scala

Enrich My Library – Extension Methods

(At the time of writing of this article, this Scala technique was called “Pimp My Library”, which was also reflected in its title. This term is now obsolete and discouraged and has been replaced with a much clearer and less offensive term: “Extension Methods”. This article has been edited to reflect this).

Methods are an efficient way of reducing code duplication and making our code cleaner. What happens if a class that you don’t own (i.e.: any class of the Standard Scala Library) doesn’t have a particular method that could make your life a lot easier — and your code a lot more readable? This article will describe how we can efficiently enrich an existing Scala library and how to seamlessly use it in our code.

How to Enrich an Existing Class

Let’s assume that in our application we often need to complete a text with the string “Yo”.
We could write a nice method for it and import it when needed, but that does not make its usage look exactly the same as the other standard methods of the String class. Instead, by “enriching” our class, we will be able to use our method as it was actually part of the standard implementation of String.

Creating the following class will do the trick:

<code language="scala">
// in file com/daniela/sfregola/tutorial/package.scala
package com.daniela.sfregola

package object tutorial {

  implicit class ExtendedString(val text: String) extends AnyVal {
    def yofy = s"Yo $text"
  }
}
</code>

We can now use our yofy method for any String used in a class in the package com.daniela.sfregola.tutorial:

<code language="scala"> 
package com.daniela.sfregola.tutorial 

object Main extends App { 
   println("bro".yofy)
   //"Yo bro" 
} 
</code>

These are just a few lines of code, but they use quite some interesting and powerful tools of the Scala Language.
First of all, ExtendedString is inside a package object, called tutorial: the class will be automatically imported in all the files that belong to package com.daniela.sfregola.tutorial. For more information on package objects, have a look at this article.
Also, the class is implicit: this allows the compiler to seamlessly wrap an instant of a String inside ExtendedString.
Finally, we can see that our class is a subclass of AnyVal: this is a functionality introduced from Scala 2.10, called Custom Value Class: in practical terms, it makes our code a lot faster following some optimisation from the compiler.

Custom Value Classes

If we play a bit with the :javap command in the scala console we can see how the compiler disassembles our code. If we do this for a Custom Value Classes (i.e. a class that extends AnyVal) we can notice that, instead of allocating an instance for that class type, the compiler will just allocate a java.lang.String: this little trick makes our code a lot more performant as it will avoid the allocation of runtime objects…magic indeed!

Ok, so why don’t we use extends AnyVal everywhere?

The compiler translates our instance into a java.lang.String, so it could struggle if serialising/deserialising it. This approach is usually suggested only when enriching libraries: when extending an existing class, usually we are not actually creating new classes but just adding methods by wrapping an instance of the original class.

Summary

Enriching libraries is a powerful tool to enrich existing libraries. In this article, we have described how to efficiently add methods to existing classes. Also, we have briefly described the principle used by the compiler to perform runtime optimisation using Custom Value Classes.

Leave a comment