8

What is the more idiomatic way to handle an Option, map / getOrElse, or match?

val x = option map {
  value => Math.cos(value) + Math.sin(value)
} getOrElse {
  .5
}

or

val x = option match {
    case Some(value) => Math.cos(value) + Math.sin(value)
    case None => .5
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Paul Draper
  • 78,542
  • 46
  • 206
  • 285
  • 2
    This question should not be closed for being primarily opinion based. Coming from Python, I know there are hundreds of questions on SO about the most "Pythonic" (idiomatic) ways to do this. – Paul Draper Jan 30 '14 at 21:50

4 Answers4

11

You could always just look at the Scaladoc for Option:

The most idiomatic way to use an scala.Option instance is to treat it as a collection or monad and use map,flatMap, filter, or foreach:

val name: Option[String] = request getParameter "name"
val upper = name map { _.trim } filter { _.length != 0 } map { _.toUpperCase }
println(upper getOrElse "")

And a bit later:

A less-idiomatic way to use scala.Option values is via pattern matching:

val nameMaybe = request getParameter "name"
nameMaybe match {
  case Some(name) =>
    println(name.trim.toUppercase)
  case None =>
    println("No name value")
}
Vidya
  • 29,932
  • 7
  • 42
  • 70
  • 2
    I would not and do not object to that, but do note that `match` constructs compile to inline code. HOFs require first-class functions and those functions each generate a class to capture their bodies and must be instantiated each time they're used. So in those situations where overhead matters (the proverbial inner loop), the match might be called for. Also, I think most people find them more readily graspable than a HOF *when applicable*, which more or less means when their used in isolation. In a monadic chain where you'd use for comprehension, it's simply the only way. – Randall Schulz Jan 31 '14 at 00:43
  • Interesting...they didn't mention fold – Paul Draper Oct 09 '14 at 15:41
  • The opportunity to use `fold` didn't arrive Scala 2.10. Also, people will often differ on the readability of `fold` vs. `map().getOrElse()`. But I would say both are idiomatic, and both are more idiomatic than `match`. – Vidya Oct 09 '14 at 18:53
4

Use fold for this kind of map-or-else-default thing:

val x = option.fold(0.5){ value => Math.cos(value) + Math.sin(value) }
dhg
  • 52,383
  • 8
  • 123
  • 144
  • 2
    although it does answer the question from the 'idiomatic' perspective, the catamorphism on Option is hard to read. A -1 from code maintainability POV. See this discussion & conclusion on the topic: http://apache-spark-developers-list.1001551.n3.nabble.com/Option-folding-idiom-td25.html – maasg Jan 30 '14 at 22:38
  • 1
    The argument order of `fold` seems to be a sticking point in that discussion; it might be worth noting that Scalaz proves a `.cata` extension method with the expected argument order: `option.cata(value => cos(value) + sin(value), 0.5)`. By having a single parameter list it also avoids the usual hiccups with too-specific inferred types breaking stuff. – Hugh Jan 31 '14 at 00:02
1

Obviously both are valid and I don't think one is more idiomatic than the other. That being said, using map uses the fact the Option is a Monad. This can be particularly advantageous when combining two Options. Say you have two Option[Int] that you would like to add. In this case instead of doing multiple matches it is much cleaner to use map/flatMap and it's equivalent "for comprehensions". So for your example both are valid... but for other examples using map/flatMap is often much more succinct.

Some(6).flatMap(intValue => Some(5).map(intValue + _))

or

for {
   i <- Some(6)
   j <- Some(5)
} yield i + j
Andrew Cassidy
  • 2,940
  • 1
  • 22
  • 46
0

All of them have different semantics, so in your case none of them.

map applies some function to the value inside Option, if it exists (Some, not None). Basically this is how you safely work with Options, appling function on some null value is dangeroues, cause it can throw NPE, but in case with Option it just returns None.

getOrElse simply returns either it's value or default one (which you provide as an argument). It won't do anything with the value inside the Option, you can just extract it, if you have Some, or return a default one, in case of None.

and match approach i'd say is a combination of two, cause you can apply some computation on the values and extract it from the Option

4lex1v
  • 21,367
  • 6
  • 52
  • 86