Scala Options the slick way

02 Jun, 2011
Xebia Background Header Wave

The Scala Option type is key for dealing with variables that can have values or not. Most libraries and applications make use of this handy type. However, it’s usage in certain cases can lead to rather verbose code. This blog explains how to deal with this particular case in an elegant way using implicits. Read on to see how easy it is to tailor any kind of existing Scala type to perfectly fit your needs based on an example with Options.

I love the Option type in Scala. Options provide a very concise way to express whether a variable can have a value or not. Whereas a programmer can express his/her intent in Scala in an extremely concise and compact way I must admit that this is not always true when dealing with Options.
Depending whether I’m dealing with a Some() a want to convert the value of type X to a value of another type Y. Otherwise, in case it’s a None, I want to provide a default value of the target type Y. When writing Scala code I find myself using this construct quite often. To illustrate this let’s consider the following snippet:

val myOpt:Option[Int] = Some(1234)
val converted = myOpt match {
case Some(v) => v.toString.reverse.mkString("-")
case None => "unknown"
assert("4-3-2-1" == converted)

Basically, what we want to achieve here is a conversion from Int to a String depending whether the Option is of type Some(Int). Otherwise we want to provide a default value of “unkown”.
This is the only case I can think of where I can associate Scala with boilerplate code. Four lines of code to perform a simple conversion or provide a default value depending whether we are dealing with a Some or a None is quite a lot. The good news is, that there is an alternative. By using other methods of the Option API I could convert this into a one-liner as follows:

val myOpt:Option[Int] = Some(1234)
val converted = if(myOpt.isDefined) myOpt.get.toString.reverse.mkString("-") else "unknown"
assert("4-3-2-1" == converted)

Apparently, it’s not that hard to put the desired conversion in one line of code, however, using conditional logic to achieve the desired result tempers my enthusiasm considerably. What I actually want is the following:

val myOpt:Option[Int] = Some(1234)
val converted = myOpt <strong>some<em>?</strong> (</em>.toString.reverse.mkString("-")) <strong>orNone</strong> "unknown"
assert("4-3-2-1" == converted)

Personally, I would find such an API for Option very intuitive to use, concise, compact and fully OO. So, since it’s not there (yet) we have to come up with a solution ourselves. Since we want to add new functionality to an existing type without being able to modify the source code, the way to go are implicits. A possible solution looks as follows:

implicit def fromOptionToConvertedVal<a href="Option[T]">T</a> = new {
def some<em>?[R] (doWithSomeVal:(T) => R) = new {
def orNone(handleNone: => R) = o match {
case Some(value) => doWithSomeVal(value)
case None => handleNone

What is happening here? We first define an implicit function, which takes an Option as parameter. The conversion returns an anonymous object, which contains one function with the name some?. Any name would do of course. The some? function is a higher order function that takes a function parameter of type T, which is the same as the one of the Option. The function parameter of some? then returns a new type of R, since we want to convert the initial value of type T to R.
Instead of doing something within the function body, we return another anonymous object with the counterpart of some? called orNone. The orNone function takes a call-by-name argument. The body of the orNone does the actual work. Based on whether the Option is a Some the function parameter of some? is executed otherwise the call-by-name argument of the orNone, which leads to the desired result.
Bottom line: if you are missing something in any library you use in Scala, implicits provide you the perfect means to add everything you like so that it works for you. That is the real ‘option’ Scala offers you 😉


Get in touch with us to learn more about the subject and related solutions

Explore related posts