Why getOrElse with map is possibly worse than fold with Option[T]s

Option[T] is probably everyone’s favorite monad in Scala. It’s basically the same as Maybe in Haskell. It provides a nice functional interface with nullable types on the JVM. It also supports type information to help the compiler help us catch errors before runtime. It supports all container-type methods, including foreach, map, getOrElse, head, etc. To transform the value inside the Option, I used to do the following:

scala> val o: Option[Int] = Some(3)
o: Option[Int] = Some(3)

scala> o.map { _ * 2 }
res1: Option[Int] = Some(6)

As you can see, map actually returns a new Option which totally makes sense, as it can’t know beforehand that there’s actually a value:

scala> val x: Option[Int] = None
x: Option[Int] = None

scala> x.map{ _ * 2 }
res3: Option[Int] = None

The usual response to that would be using a getOrElse on the new Option returned by map:

scala> o.map { _ * 2 }.getOrElse(0)
res5: Int = 6

scala> x.map{ _ * 2 }.getOrElse(0)
res6: Int = 0

The only problem with this approach is that because getOrElse needs to be generic enough, we can actually return any type from it. Here’s the signature of the method: def getOrElse[B >: A](default: => B): B, and this lets us do this kind of shenanigans:

scala> x.map{ _ * 2 }.getOrElse("no")
res7: Any = no

Combining this with type deduction, we can actually write code that long lost type information, and would result in runtime errors.

Now comes fold to the rescue! With the following signature def fold[B](ifEmpty: => B)(f: (A) => B): B it can actually achieve the same as map+getOrElse:

scala> o.fold(0){ _ * 2 }
res8: Int = 6

scala> x.fold(0){ _ * 2 }
res9: Int = 0

But saves us from doing possibly stupid things:

scala> x.fold("no"){ _ * 2 }
:13: error: type mismatch;
 found   : Int
 required: String
       x.fold("no"){ _ * 2 }

since it requires that both the mapping and the default value have the same type. Plus, it’s more concise and it’s only one method invocation.

Yes, there are cases when we actually want to change the type. For those cases getOrElse can be used; but most of the time using fold is just much safer.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s