Knows Not Much
Knows Not Much

Reputation: 31576

Avoiding nested Ifs when working with multiple Options and Eithers

When I am coding with options I find the fold method very useful. Instead of writing if defined statements I can do

opt.fold(<not_defined>){ defined => }

this is good. but what to do if we are working with multiple options. or multiple eithers. Now I have to resort to writing code like

if (x.isDefined && y.isRight) {
  val z = getSomething(x.get)
  if (z.isDefined) {
    ....

Depending on the number of things involved, this code becomes very nested.

is there a functional trick to make this code a little un-nested and concise.... like the fold operation above?

Upvotes: 1

Views: 263

Answers (2)

Josef Vlach
Josef Vlach

Reputation: 379

Cases when .isDefined is followed by .get call can be refactored using custom extractors for pattern matching:

def getSomething(s: String): Option[String] = if (s.isEmpty) None else Some(s.toUpperCase)

object MyExtractor {
  def unapply(t: (Option[String], Either[Int, String])): Option[String] =
    t match {
      case (Some(x), Right(y)) => getSomething(x)
      case _ => None
    }
}

val x: Option[String] = Some("hello world")
val y: Either[Int, String] = Right("ok")

(x, y) match {
  case MyExtractor(z) => z // let's do something with z
  case _ => "world"
}
// HELLO WORLD

We managed to get rid of all .isDefined, .get and even .right calls by replacing them by explicit pattern matching thanks to our custom extractor MyExtractor.

Upvotes: 1

pedrorijo91
pedrorijo91

Reputation: 7865

have you tried for comprehension? Assuming you don't want to treat individual errors or empty optionals:

import scala.util._

val opt1 = Some("opt1")
val either2: Either[Error, String] = Right("either2")
val try3: Try[String] = Success("try3")

for {
  v1 <- opt1
  v2 <- either2.right.toOption
  v3 <- try3.toOption
} yield {
  println(s"$v1 $v2 $v3")
}

Note that Either is not right biased, so you need to call the .right method on the for comprehension (I think cats or scalaz have a right biased Either). Also, we are converting the Either and the Try to optionals, discarding errors

Upvotes: 1

Related Questions