Scala Option.fold vs Option.map/getOrElse

Scala Option offers two different ways to handle an Option value.

Option.map/getOrElse

val name: Option[String] = request getParameter "name"
name map { _.toUpperCase } getOrElse ""

Option.fold

val name: Option[String] = request getParameter "name"
name.fold("") { _.toUpperCase }

On the spark-dev mailing list, there was a discussion on using Option.fold instead of Option.map/getOrElse combination.

Two idioms look almost the same, but people seem to prefer one over the other for readability reasons. Here is the summary of the discussion:

  • Option.getOrElse/map is a more idiomatic Scala code because Option.fold was only introduced in Scala 2.10.
  • Fold on Option is not obvious to most developers.
  • Option.fold is not readable.
    • Reverses the order of Some vs None.
    • Putting the default condition first there makes it not as intuitive.
    • When code gets long, the lack of an obvious boundary with two closures is confusing. (“} {” compared to getOrElse)
  • Fold is a more functional idiom in general.

It seems people are getting used to functional idioms such as map and filter, but still are reluctant to accept more functional idioms such as Option.fold.

I prefer Option.getOrElse/map because I think putting the default value first is not intuitive and much of Scala code is already written with Option.getOrElse/map. However, both options are fine as long as only one style is used through the project. Consistency is more important than taste!

Advertisements

4 thoughts on “Scala Option.fold vs Option.map/getOrElse

  1. Naming the argument (ifEmpty=””) goes some way to improving the readability. Scalaz has cata which is identical in behaviour but also has the arguments in the sensible format.

  2. getOrElse can be dangerous. It is under no compultion to return the same type that you are wrapping in an option. All it has to do is return a subtype of whatever is expected in the context from which getOrElse is called (which might even be Any, if you haven’t been careful).

    Some(3).getOrElse(“four”)
    res1: Any = 3

    None.getOrElse(“four”)
    res2: String = four

    fold cannot commit this sin:

    Some(3).fold(“four”) (x => x)
    :1: error: type mismatch;
    found : Int
    required: String

  3. I just noticed that you are using “Option.getOrElse/map” not “Option.map/getOrElse”
    saying “putting the default value first is not intuitive” in the end of this article.
    This is a little bit awkward. 🙂

  4. I think fold is perfectly fine and objections seem to have more to do with psychology and comfort level than anything else (meaning people resist change and new ways of doing things as fold came in later).
    Any programmer should be used to the idiom “do a guard first and then do the useful stuff afterwards” and that’s what fold does. Say, you have a recursive function on a list and check for empty or size 1 as special case first and return, and then handle the general recursion as next (harder and normal) step? This fits the same pattern as fold to me.

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