Reputation: 391
I've been trying to find a nice way to combine a chain of Try in Scala with subsequent resources clean up. What I ended up with looked something like this (powered by scalaz)
for {
x <- \/.fromTryCatchNonFatal(...)
y <- \/.fromTryCatchNonFatal(...).leftMap( /* clean up x */ )
z <- \/.fromTryCatchNonFatal(...).leftMap( /* clean up x and y */ )
// clean up everything
} yield (...)
the problem with this approach is that I could miss some cleanup for some particular case which is likely to happen if you have much more than 3 Try blocks. Not to mention that it looks bulky and ugly.
So I came up with a wrapper for Scala Try using State and Either monads offered by scalaz.
What I ended up with was looking like this:
val try = for {
a <- Try(/* no resources allocated here */).noRes
c <- Try(20).res { x => /** create DB connection */ }.res(/* release DB connection */)
} yield (..)
val result: Throwable \/ T = try.safeEval
What you benefit from doing things this way is you have a guarantee that all your resources will be released both in case of exception and in case of successful computation.
This code is not ready for production use, definitely needs some improvements.
What do you think, is this approach viable in your opinion? Would you recommend doing same thing differently?
Upvotes: 2
Views: 135
Reputation: 149538
This is exactly what Bracket
is for. It is defined in cats-effect and is an extension of MonadError
which provides you with safe resource handling. For example:
val foo =
IO.pure(42).bracket(int => /* use resource */ ???)(_ => /* release resource */ ???)
Upvotes: 2