In Scala, there are a lot of cool things - too many to list. Among them is something borrowed from Haskell; the Maybe, spelt Option in Scala, which itself is based on the concept of computing via monads.

The reason why Option is awesome is that, if used properly, it largely frees the programmer from having to worry about various variables being in states of nothingness (Nil, null, etc). Without fail, every programmer has at one point or another written things like thing.nil? ? do_nothing : do_something …. all over the place. The point (in my mind, at least) of Option is to free us from having to do this in as many places as possible.

Many libraries in Scala, such as Scala-Redis are made with the assumption that the programmer knows how to deal with Option and return results wrapped in either Some[List[T]] or None. That said, how to work with these types of results is not exactly straight forward for someone coming from other languages that don’t have such constructs, so I’ve written down some of my thoughts.

As an example, let’s try tackling the issue of how to use a result like the one that comes from Scala-Redis: Some[List[T]].

To keep things simple, assume we have a val maybeList = Some(List(1,2,3)) and we want to increment each member of the list inside the Option, and want to return anotherOption with the incremented list inside. While we could potentially do pattern matching to check if the Option is a None, we would prefer to take advantage of the patterns afforded to us by the fact that we’re dealing with an Option. This means using map, flatMap and for.

Based on what official Scala documentation on Options tells us, we have

Scala option-wrapped collections (processing_option_wrapped_collections.scala) download
1
2
3
4
5
6
7
8
9
10
11
12
13
def incrementMaybeList(maybeList: Option[List[Int]], increment: Int = 1): Option[List[Int]] = {
  maybeList.map{list =>
    list.map(_ + increment)
  }
}

def incrementMaybeListFor(maybeList: Option[List[Int]], increment: Int = 1): Option[List[Int]] = {
  for {
    list <- maybeList
  } yield {
    list map (_ + 1)
  }
}

There are two versions that we can choose from; one using map and another using for. In essense, they are the same, because for-comprehensions boil down to appropriate map and flatMap methods anyway. This also means that sometimes you may get funky errors with type mismatch errors, for which a good rule of thumb is to remember that for comprehensions will try to return the type of the collection of the first generator

Using the code above, we can do:

1
2
3
4
5
6
7
val maybeList = Some(List(1,2,3))
val incrementedMaybeList = incrementMaybeList(maybeList)
// => incrementedMaybeList: Option[List[Int]] = Some(List(2, 3, 4))

val maybeListNone = None
val incrementedMaybeList = incrementMaybeList(maybeListNone)
// => incrementedMaybeList: Option[List[Int]] = None

The fact that calling incrementMaybeList with maybeList worked should not be surprising, but notice how maybeListNone didn’t cause the function to throw up. This is because calling methods like map or using for-comprehnsion on Options that are None immediately return None instead of proceeding to run internal logic. No need to write if/else guards !

By building and using functions like incrementMaybeList, where an Option is processed and an Option is returned throughout the code, one can stop worrying about Nothingness (for the most part), because they can be chained together.

1
2
incrementMaybeList(incrementMaybeList(None))
// => Option[List[Int]] = None

When the time comes to actually do something with those Option-wrapped results without returning another value, once again, its time to break out for-comprehensions.

1
2
3
4
5
6
7
8
9
10
11
// Unimaginatively print the incremented results

for{
  list <- incrementList(Some(List(1,2,3)))
  item <- list
} println(item)

for{
  list <- incrementMaybeList(incrementMaybeList(None))
  item <- list
} println(item)

Conclusion

Options free the programmer from worrying about Nothingness and thus from writing tons of boilerplate nothingness checks in our code. This blog post talks about a simplish, but applicable example on how to deal with Option in Scala.

Comments