scala.Option Cheat Sheet


Many people who are coming in to Scala first encounter the Option type, which may be thought of (among other things) as a type-safe null. They also encounter pattern matching as both a new and (relatively) powerful concept, but also one that is easy to understand. This leads to quite a lot of use of pattern matching and often excessively so in what I have observed.

Particularly with a type as trivial as Option, it is almost always possible to do away with pattern matching by using a higher-order function. Use of this function is typically preferred over pattern matching as tighter code. In fact, it is important to observe that it is possible to encapsulate all forms of pattern matching over Option with one simple higher-order function:

def option[A, X](o: Option[A])(none: => X, some: => A => X): X = ...

Then, all functions can be written in terms of this one and needn’t pattern match at all. For example, consider Option.map:

def map[A, B](o: Option[A], f: A => B) =
  option(o, None, a => Some(f(a)))

In this post, I am going to give some common uses of pattern matching, which many developers might find themselves performing, followed by the use of a function that already exists on Option that encapsulates that given form of pattern matching. If you find yourself using pattern matching in a form not listed below, but feel it could be abstracted, then chances are that such a function exists in the Scalaz extension to scala.Option.

I will use the identifier foo below to denote any particular function, including many functions composed, for example, foo(x) may represent the composition of two functions f and g: f(g(x)). I also use the identifier option to denote any value of the type scala.Option.

I hope this helps :)

  • flatMap

    option match {
      case None => None
      case Some(x) => foo(x)
    }

    This code is equivalent to:

    option.flatMap(foo(_))
  • map

    option match {
      case None => None
      case Some(x) => Some(foo(x))
    }

    This code is equivalent to:

    option.map(foo(_))
  • foreach

    option match {
      case None => {}
      case Some(x) => foo(x)
    }

    This code is equivalent to:

    option.foreach(foo(_))
  • isDefined

    option match {
      case None => false
      case Some(_) => true
    }

    This code is equivalent to:

    option.isDefined
  • isEmpty

    option match {
      case None => true
      case Some(_) => false
    }

    This code is equivalent to:

    option.isEmpty
  • forall

    option match {
      case None => true
      case Some(x) => foo(x)
    }

    This code is equivalent to:

    option.forall(foo(_))
  • exists

    option match {
      case None => false
      case Some(x) => foo(x)
    }

    This code is equivalent to:

    option.exists(foo(_))
  • orElse

    option match {
      case None => foo
      case Some(x) => Some(x)
    }

    This code is equivalent to:

    option.OrElse(foo)
  • getOrElse

    option match {
      case None => foo
      case Some(x) => x
    }

    This code is equivalent to:

    option.getOrElse(foo)

    toList

    option match {
      case None => Nil
      case Some(x) => x :: Nil
    }
    option.toList

14 Responses to “scala.Option Cheat Sheet”

  1. Erik van Oosten Says:

    The link to type Option is wrong, please delete the first “http://”.

  2. Erik van Oosten Says:

    Sorry, actually, the second “http//” should be deleted.

  3. Alex Boisvert Says:

    Great post Tony. I won’t be using match on Option[_] anymore!

  4. Tony Morris Says:

    Thanks Erik, fixed :)

  5. nosewheelie » Blog Archive » scala.Option Cheat Sheet Says:

    [...] Source: scala.Option Cheat Sheet. [...]

  6. Daniel Jimenez Says:

    Great cheatsheet.

    I’m wondering, how would one use Option in the case described in the first comment here (http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-2#numcomments)?

    (Copied from there)

    abstract class Shape {
    ..var fillColor:Option[Color] = None
    ..// etc
    }
    
    class Circle(var radius:Int) extends Shape {
    ..def draw(g:Graphics):Unit = fillColor match {
    ....case None =>
    ......g.drawCircle(0, 0, radius / 2, radius / 2)
    ....case Some(color) => {
    ......g.setColor(color);
    ......g.fillOval(0, 0, radius / 2, radius / 2)
    ....}
    ..}
    }
    

    I suspect the problem is the inherent imperative-ness of requiring setColor to be called before fillOval. Can I get around this in Scala using the examples above, or is there more to the story?

  7. Tony Morris Says:

    Just a note for anyone that cares; I have updated this post with a reference to two additional entries that use the forall and exists methods on Option.

  8. Jörn Zaefferer Says:

    Is there any way to replace this?

    User.find(By(User.email, email)) match {
    case Full(dbuser) if (dbuser.password.match_?(password)) => User.logUserIn(dbuser)
    case Full(dbuser) => error(”wrong password”)
    case Empty => notice(”sending verification mail”)
    }

    Here its a Can with Full instead of Some, but that shouldn’t be important.

  9. Tony Morris Says:

    Hi Jörn, there is a way of removing that but it’s very specific. This is because of the guard in your first match. You could transform that code to put the guard on the right side of the case match, so then you’d have:

    case Full(dbuser) => if (dbuser.password.match_?(password)) User.logUserIn(dbuser) else error(”wrong password”)
    case Empty => notice(”sending verification mail”)
    

    Then of course, you could just call the option method or equivalent for Can. Then you might want to get even more specific by decomposing your if. Since you can write if yourself in Scala, you can then apply certain specialisations to it. I’ll let you write your Scala if, then various specialisations without giving the answer away :)

  10. Seth Tisue Says:

    Thank you. This is helpful.

  11. Seth Tisue Says:

    The equivalence you give for flatMap only holds if the return type of foo(x) is compatible with Option. Right?

  12. Tony Morris Says:

    Hello Seth,
    Yes that is correct. All examples are assumed to type-check.

  13. John Simmons Says:

    Nice examples. Several questions:

    1. I don’t understand the def option[A,X] method, since no body is given. Is this something generic that should be so obvious I can write it myself, or is it something specific to a given situation?

    2. Methods forall and exists are not listed in the scaladoc for Option, but I tried them and they do work. Where do they come from? Is there an implicit conversion happening here?

    3. Most seriously, I have a pattern that does not match any of the patterns given:

    def process(o: Option[A], cc: C): B =
    o match {
    case Some(a) => f (a, cc) // value of type B that depends on both a and cc
    case None => g(cc) // value of type B that depends only on cc
    }

    The only way that I see to replace this match is with

    o.map(f(_,cc)).getOrElse(g(cc))

    This seems less efficient since it uses two calls, and the first call constructs an extra Option[B] to which to apply the second call.

  14. Tony Morris Says:

    Hi John,
    Thanks for the feedback.

    1) The option method is intended to encapsulate the deconstruction of the Option type. Consider that Option has two case class constructors, None and Some, therefore, the method has two arguments. Furthermore, one of the constructors (Some) takes a single argument, therefore, one of the method arguments is a function that takes 1 argument.

    It might be a good exercise to attempt to write the option method while maintaining the given type signature. You will use pattern matching to do so. The point is, however, that you have encapsulated the most general form of Option deconstruction and so you needn’t (theoretically) ever manually deconstruct Option again with pattern matching.

    2) There is an implicit from Option to Iterable in the Option object. http://www.scala-lang.org/docu/files/api/scala/Optionobject.html#option2Iterable%28Option%5BA%5D%29

    3) It may be the case that you have a general deconstruction form where you use the hypothetical option method. Then, are there any recurring patterns? If so, write a more specific function.

    There is no problem with your call to map then getOrElse. Efficiency should not be considered here in favour of the compiler performing what is called ‘fusing’. In practice though, the compiler will not fuse this expression, nor will the efficiency cost be negligible to the gain in expressivity.

    Finally, you may want to ‘compose’ these functions yourself and I recommend you do so even if just for your own satisfaction. You can implement it by calling map then getOrElse with the appropriate arguments. Then, if one day performance becomes a huge issue, change the implementation to use pattern matching. Doing this is essentially manual fusing.

    I hope this helps; ask more questions if you need.

Leave a Reply