Question

I need to use some Java library, which might throw some exceptions in one method and return error codes in another set of methods. So far it leads to the ugly code like

val txn = mgr.prepareTransaction()
val accessRecord = txn.readByQuery(...)
var state : Either[MyError, Result] = null //
try {
  // do something here
  val result = txn.runCodeWithin(new Callable[Result]() {...})
  if (result == -1) {
    state = Left(CanNotReadRecord)
  } else {
    state = Right(txn.getCachedRecord())
  }
} catch {
  case e: Exception => state = Left(GeneralError(e))
} finally {
  state match {
    case Right(_) => txn.commit();
    case _        => txn.rollback();
  }
}

I mostly interested in getting rid of state as var and ability to check the state in finally block. Please advice.

Was it helpful?

Solution

Scala 2.10 introduced the Try class, which is a more functional replacement to the use case of Either[Throwable, Result]. It's got all of the usual monad ops (the things that make for-comprehensions work), and some other helpful methods. (check out the docs for Try here)

Here's a possible re-implementation of your code, using Try, and replacing CanNotReadRecord with a CanNotReadRecordException. It should be functionally equivalent to your example, with the exception of that replacement.

def txResults(txn: Transaction): Try[Record] = for {
    result <- Try{ txn.runCodeWithin(...) }
    checked <- result match {
        case -1 => Failure( new CanNotReadRecordException )
        case _ => Success( txn.getCachedRecord )
    }
} yield checked

txResults(txn) match {
    case Success(record) => txn.commit()
    case Failure(e) => txn.rollback() //and maybe handle `e`
}

OTHER TIPS

The Scala ARM (Automatic Resource Management) library handles all this sort of thing elegantly and in a completely air-tight manner.

Check it out.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top