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
-
flatMapoption match { case None => None case Some(x) => foo(x) }
This code is equivalent to:
option.flatMap(foo(_))
-
mapoption match { case None => None case Some(x) => Some(foo(x)) }
This code is equivalent to:
option.map(foo(_))
-
foreachoption match { case None => {} case Some(x) => foo(x) }
This code is equivalent to:
option.foreach(foo(_))
-
isDefinedoption match { case None => false case Some(_) => true }
This code is equivalent to:
option.isDefined -
isEmptyoption match { case None => true case Some(_) => false }
This code is equivalent to:
option.isEmpty -
foralloption match { case None => true case Some(x) => foo(x) }
This code is equivalent to:
option.forall(foo(_))
-
existsoption match { case None => false case Some(x) => foo(x) }
This code is equivalent to:
option.exists(foo(_))
-
orElseoption match { case None => foo case Some(x) => Some(x) }
This code is equivalent to:
option.OrElse(foo)
-
getOrElseoption match { case None => foo case Some(x) => x }
This code is equivalent to:
option.getOrElse(foo)
toListoption match { case None => Nil case Some(x) => x :: Nil }
option.toList
January 16th, 2008 at 8:58 pm
The link to type Option is wrong, please delete the first “http://”.
January 16th, 2008 at 9:04 pm
Sorry, actually, the second “http//” should be deleted.
January 17th, 2008 at 3:00 am
Great post Tony. I won’t be using match on Option[_] anymore!
January 17th, 2008 at 6:07 am
Thanks Erik, fixed
January 17th, 2008 at 10:21 am
[...] Source: scala.Option Cheat Sheet. [...]
January 19th, 2008 at 1:56 am
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?
February 13th, 2008 at 4:12 pm
Just a note for anyone that cares; I have updated this post with a reference to two additional entries that use the
forallandexistsmethods onOption.February 19th, 2008 at 3:46 am
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.
February 19th, 2008 at 8:01 am
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:
Then of course, you could just call the
optionmethod 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 awayApril 10th, 2008 at 4:03 am
Thank you. This is helpful.
April 25th, 2008 at 6:17 am
The equivalence you give for flatMap only holds if the return type of foo(x) is compatible with Option. Right?
April 25th, 2008 at 9:22 am
Hello Seth,
Yes that is correct. All examples are assumed to type-check.
June 21st, 2008 at 5:04 am
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.
June 21st, 2008 at 6:26 am
Hi John,
Thanks for the feedback.
1) The
optionmethod is intended to encapsulate the deconstruction of theOptiontype. Consider thatOptionhas two case class constructors,Noneand 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
optionmethod 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 ofOptiondeconstruction and so you needn’t (theoretically) ever manually deconstructOptionagain with pattern matching.2) There is an implicit from
OptiontoIterablein theOptionobject. http://www.scala-lang.org/docu/files/api/scala/Optionobject.html#option2Iterable%28Option%5BA%5D%293) It may be the case that you have a general deconstruction form where you use the hypothetical
optionmethod. 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
mapthengetOrElsewith 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.