How is functions with side-effects best handled in for-comprehensions in Scala?
I have a for comprehension that starts by creating a kind of resource (x) by calling a function f1. This resource has a close-method that needs to be called at the end but also if the for-comprehension fails somehow (unless.
So we have something like:
import scala.util.{Try,Success,Failure}
trait Resource {
def close() : Unit
}
// Opens some resource and returns it as Success or returns Failure
def f1 : Try[Resource] = ...
def f2 : Try[Resource] = ...
val res = for {
x <- f1
y <- f2
} yield {
(x,y)
}
Where should I call the close method? I can call it at the end of the for-comprehension as the last statement (z <- x.close), in the yield-part, or after the for-comprehension (res._1.close). None of them ensures that close is called if an error occurs (e.g. if f2 fails). Alternatively, I could separate
x <- f1
out of the for-comprehension like this:
val res = f1
res match {
case Success(x) => {
for {
y <- f2
}
x.close
}
case Failure(e) => ...
:
That would ensure the call of close but is not very nice code. Is there not a smarter and more clean way to achieve the same?