3

I'm finding that I often have to chain together functions that work on an Option and return a different Option that look something like this:

if(foo.isDefined) someFunctionReturningOption(foo.get) else None

Is there a cleaner way to do this? This pattern gets quite verbose with more complicated variables.

I'm seeing it a fair bit in form handling code that has to deal with optional data. It'll insert None if the value is None or some transformation (which could potentially fail) if there is some value.

This is very much like the ?. operator proposed for C#.

Community
  • 1
  • 1
Kat
  • 4,645
  • 4
  • 29
  • 81

4 Answers4

6

You can use flatMap:

foo.flatMap(someFunctionReturningOption(_))

Or in a for-comprehension:

for {
    f <- foo
    r <- someFunctionReturningOption(f)
} yield r

The for-comprehension is preferred when chaining multiple instances of these functions together, as they de-sugar to flatMaps.

Michael Zajac
  • 55,144
  • 7
  • 113
  • 138
4

There're a lot of options (pun intended) but for comprehensions, I guess, is the most convinient in case of chains

for { 
  x <- xOpt
  y <- someFunctionReturningOption(x)
  z <- anotherFunctionReturningOption(y)
} yield z
om-nom-nom
  • 62,329
  • 13
  • 183
  • 228
2

You're looking for flatMap:

foo.flatMap(someFunctionReturningOption)

This fits into the general monadic structure, where a monad wrapping a type uses flatMap to return the same type (e.g. flatMap on Seq[T] returns a Seq).

Ben Reich
  • 16,222
  • 2
  • 38
  • 59
2

Option supports map() so when x is an Option[Int] this construct:

if (x.isDefined)
  "number %d".format(x.get)
else
  None

is easier to write as:

x map (i => "number %d".format(i))

map will keep None unmodified, but it will apply the function you pass to it to any value, and wrap the result back into an Option. For example note how 'x' gets converted to a string message below, but 'y' gets passed along as None:

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

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

scala> x map (i => "number %d".format(i))
res0: Option[String] = Some(number 3)

scala> y map (i => "number %d".format(i))
res1: Option[String] = None
Giorgos Keramidas
  • 1,818
  • 14
  • 9