Nico
Nico

Reputation: 391

Safe Try with clean up

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.

Full code is here on GitHub

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

Answers (1)

Yuval Itzchakov
Yuval Itzchakov

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

Related Questions