Chaining scala Try instances that contain Options

Viewed 1859

I am trying to find a cleaner way to express code that looks similar to this:

def method1: Try[Option[String]] = ???
def method2: Try[Option[String]] = ???
def method3: Try[Option[String]] = ???

method1 match
{
  case f: Failure[Option[String]] => f
  case Success(None) =>
  method2 match
    {
      case f:Failure[Option[String]] => f
      case Success(None) =>
      {
        method3
      }
      case s: Success[Option[String]] => s
    }
  case s: Success[Option[String]] => s
}

As you can see, this tries each method in sequence and if one fails then execution stops and the base match resolves to that failure. If method1 or method2 succeeds but contains None then the next method in the sequence is tried. If execution gets to method3 its results are always returned regardless of Success or Failure. This works fine in code but I find it difficult to follow whats happening.

I would love to use a for comprehension

for
{
  attempt1 <- method1
  attempt2 <- method2
  attempt3 <- method3
}
  yield
{
  List(attempt1, attempt2, attempt3).find(_.isDefined)
}

because its beautiful and what its doing is quite clear. However, if all methods succeed then they are all executed every time, regardless of whether an earlier method returns a usable answer. Unfortunately I can't have that.

Any suggestions would be appreciated.

5 Answers

From this blog:

def riskyCodeInvoked(input: String): Int = ???

def anotherRiskyMethod(firstOutput: Int): String = ???

def yetAnotherRiskyMethod(secondOutput: String): Try[String] = ???

val result: Try[String] = Try(riskyCodeInvoked("Exception Expected in certain cases"))
  .map(anotherRiskyMethod(_))
  .flatMap(yetAnotherRiskyMethod(_))

result match {
  case Success(res) => info("Operation Was successful")
  case Failure(ex: ArithmeticException) => error("ArithmeticException occurred", ex)
  case Failure(ex) => error("Some Exception occurred", ex)
}

BTW, IMO, Option is no need here?

Related