Question

I have a Scala Option[T]. If the value is Some(x) I want to process it with a a process that does not return a value (Unit), but if it is None, I want to print an error.

I can use the following code to do this, but I understand that the more idiomatic way is to treat the Option[T] as a sequence and use map, foreach, etc. How do I do this?

opt match {
  case Some(x) => // process x with no return value, e.g. write x to a file
  case None => // print error message
}
Was it helpful?

Solution

Scala's Option is, sadly, missing a method to do exactly this. I add one:

class OptionWrapper[A](o: Option[A]) {
  def fold[Z](default: => Z)(action: A => Z) = o.map(action).getOrElse(default)
}
implicit def option_has_utility[A](o: Option[A]) = new OptionWrapper(o)

which has the slightly nicer (in my view) usage

op.fold{ println("Empty!") }{ x => doStuffWith(x) }

You can see from how it's defined that map/getOrElse can be used instead of pattern matching.

Alternatively, Either already has a fold method. So you can

op.toRight(()).fold{ _ => println("Empty!") }{ x => doStuffWith(x) }

but this is a little clumsy given that you have to provide the left value (here (), i.e. Unit) and then define a function on that, rather than just stating what you want to happen on None.

The pattern match isn't bad either, especially for longer blocks of code. For short ones, the overhead of the match starts getting in the way of the point. For example:

op.fold{ printError }{ saveUserInput }

has a lot less syntactic overhead than

op match {
  case Some(x) => saveUserInput(x)
  case None => printError
}

and therefore, once you expect it, is a lot easier to comprehend.

OTHER TIPS

I think explicit pattern matching suits your use case best.

I'd recommend to simply and safely use opt.get which itself throws a NoSuchElementException exception if opt is None. Or if you want to throw your own exception, you can do this:

val x = opt.getOrElse(throw new Exception("Your error message"))
// x is of type T

as @missingfaktor says, you are in the exact scenario where pattern matching is giving the most readable results. If Option has a value you want to do something, if not you want to do something else.

While there are various ways to use map and other functional constructs on Option types, they are generally useful when:

you want to use the Some case and ignore the None case e.g. in your case

opt.map(writeToFile(_)) //(...if None just do nothing)

or you want to chain the operations on more than one option and give a result only when all of them are Some. For instance, one way of doing this is:

val concatThreeOptions = 
for {
  n1 <- opt1
  n2 <- opt2
  n3 <- opt3
} yield n1 + n2 + n3 // this will be None if any of the three is None
                     // we will either write them all to a file or none of them

but none of these seem to be your case

Pattern matching is the best choice here.

However, if you want to treat Option as a sequence and to map over it, you can do it, because Unit is a value:

opt map { v =>
  println(v) // process v (result type is Unit)
} getOrElse {
  println("error")
}

By the way, printing an error is some kind of "anti-pattern", so it's better to throw an exception anyway:

opt.getOrElse(throw new SomeException)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top