Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to do finally with Try? [duplicate]

I'm new to Scala and looked at source code of Try::apply

def apply[T](r: => T): Try[T] =
  try Success(r) catch {
    case NonFatal(e) => Failure(e)
  }

It simply catches non-fatal exceptions. But what if I need finally clause? Is it possible to emulate it with Try in a functional way? I mean something like

try{
   //acquire lock
   //do some
} finally {
  // release lock
}

with

Try{
   //acquire lock
   //do some
} 
//Now how to release?
like image 384
St.Antario Avatar asked Jan 04 '23 21:01

St.Antario


2 Answers

Something similar was already answered here.

TLTR; There is no standard way to do that with the Try monad.

The usual workaround is something like this:

def use[A <: { def close(): Unit }, B](resource: A)(code: A ⇒ B): B =
    try {
        code(resource)
    } finally {
        resource.close()
    }

That you can use like:

val path = Paths get "/etc/myfile"
use(Files.newInputStream(path)) { inputStream ⇒
    val firstByte = inputStream.read()
    ....
}

Another approach which is explained here, implies that you "extend" the standard 'Try' by adding an additional method 'withRelease'

implicit class TryOps[A <: { def close(): Unit }](res: Try[A]) {
  def withRelease() = res match {
    case Success(s) => res.close(); res
    case Failure(f) => res.close(); res
  }
}

Then,

Try {
   val inputStream = Files.newInputStream(path))
   ...
   inputStream
}.withRelease()
like image 72
fGo Avatar answered Jan 06 '23 11:01

fGo


Since Try resolves to a value and it doesn't unwind the stack when something fails, you can simply perform the cleanup operations after Try has executed. For example:

val someLock = ??? // acquire some lock
val result = Try {
  // do something and return a result
}
someLock.release()

If you prefer, you can roll your own helper to keep everything into a single expression:

def withLock[A](f: Lock => A): Try[A] = {
  val lock = ??? // acquire the lock
  val res = f(lock)
  lock.release()
}

and then you can write:

val res = withLock { lock =>
 // some operation
}

This is usually refered to as loan pattern.

like image 42
Gabriele Petronella Avatar answered Jan 06 '23 12:01

Gabriele Petronella