While dealing with error-handling in Scala, I came to the point where I asked myself, whether Try
s in a for-comprehension make sense.
Please regard the unit test given below. This test shows two approaches:
- The first approach (with
call
) embeds the methodsfooA
andfooB
, which return regularString
s, into aTry
construct. - The second approach (
tryCall
) uses a for-comprehension that uses methodstryFooA
andtryFooB
, which returnTry[String]
each.
For what reason should one prefer the for-comprehension variant with tryCall
over the call
-variant?
test("Stackoverflow post: Try and for-comprehensions.") {
val iae = new IllegalArgumentException("IAE")
val rt = new RuntimeException("RT")
import scala.util.{Try, Success, Failure}
def fooA(x1: Int) : String = {
println("fooA")
if (x1 == 1) "x1 is 1" else throw iae
}
def fooB(x2: Int) : String = {
println("fooB")
if (x2 == 1) "x2 is 1" else throw rt
}
def tryFooA(x1: Int) : Try[String] = {
Try {
println("tryFooA")
if (x1 == 1) "x1 is 1" else throw iae
}
}
def tryFooB(x2: Int) : Try[String] = {
Try {
println("tryFooB")
if (x2 == 1) "x2 is 1" else throw rt
}
}
def call( x1: Int, x2: Int ) : Try[String] = {
val res: Try[String] = Try{
val a = fooA(x1)
val b = fooB(x2)
a + " " + b
}
res
}
def tryCall( x1: Int, x2: Int ): Try[String] = {
for {
a <- tryFooA(x1)
b <- tryFooB(x2)
} yield (a + " " + b)
}
assert( call(0,0) === tryCall(0,0))
assert( call(0,1) === tryCall(0,1))
assert( call(1,0) === tryCall(1,0))
assert( call(1,1) === tryCall(1,1))
}