Quick failure when using for-comprehension with scala.util.Try
exception, scala, try-catch
Solution
You can use `recover`:
import scala.util.Try
def tryEven = Try { val i = (math.random * 1000).toInt; if (i % 2 != 0) throw new Exception("odd") else i }
def tryEvenOrNeg1 = Try { val i = (math.random * 1000).toInt; if (i % 2 != 0) throw new Exception("odd") else i } recover { case exx: Exception => -1 }
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
res1: scala.util.Try[Unit] = Failure(java.lang.Exception: odd)
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
res2: scala.util.Try[Unit] = Failure(java.lang.Exception: odd)
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
res3: scala.util.Try[Unit] = Failure(java.lang.Exception: odd)
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
Got 542, -1
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
res5: scala.util.Try[Unit] = Failure(java.lang.Exception: odd)
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
res6: scala.util.Try[Unit] = Failure(java.lang.Exception: odd)
scala> for (a <- tryEven; b <- tryEvenOrNeg1) yield println(s"Got $a, $b")
Got 692, 750
I removed the `resNN` that reflected `Success(())`.
Problem
I really like `scala.util.Try` in Scala 2.10, and how it works with for-comprehension makes handling multiple steps that could go wrong easily. For example, we could use the following code to make sure we only print out that two numbers if and only if everything is under control and we get value correctly. ``` def tryA: Try[Int] = {....} def tryB: Try[Int] = {....} for { a <- tryA b <- tryB } { println (s"We got:${a+b}") } ``` But one of my concern is that this code is actually ignore any exceptions, which means it will looks like the following try-cactch block: ``` try { // ..... } catch { case _: Exception => // Swallow any exception } ``` As far as I know, there is an argument that this kind of codes is a bad smell, because no one will notice there is an exception occurs. What I would like to achieve is that still using `for` to make sure the `println` only execute if everything is OK, but if there is any exception in any steps, it will blow up and throw out the exception directly. Currently here is how I do this, but it seems less elegant because it introduce a new `Try[Unit]` object, so I'm wondering how could I make this code better? For example, is it possible to get rid of the `result` variable and `result.get` statement, but still get exception being thrown? ``` def tryA: Try[Int] = {....} def tryB: Try[Int] = {....} val result = for { a <- tryA b <- tryB } yield { println (s"We got:${a+b}") } result.get ``` Update To make thing more clear, it is the result from Scala REPL of the first code in this question. ``` scala> def tryA: Try[Int] = Success(1) tryA: scala.util.Try[Int] scala> def tryB: Try[Int] = Failure(new Exception("error")) tryB: scala.util.Try[Int] scala> for { | a <- tryA | b <- tryB | } { | println (s"We got:${a+b}") | } scala> ``` We can see that nothing happens here, even `tryB` is a `Failure` with exception. What I would like to get is an exception being thrown, and without the introduce the new `Try[Unit]` object with `yield`, is this possible?