Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Streamlining Try.recover

Tags:

scala

A pattern that that I see with some frequency in Scala is "Try unwrapping" which usually looks like this:

Try {
  input.charAt(100)    // Some error-prone calculation
} match {
  case Success(c) => c // just unwrap the value
  case Failure(e) =>
    println(e)         // log the exception
    '?'                // and provide a default value
}

This code is fine, but I'm a little bothered by the case Success(c) => c, which is basically just an identity transformation (a.k.a. noise). The soul of the transformation is the error mapping function that logs the exception and provides a default value, and that's what I want to bring to the foreground.

I can see two alternatives that get rid of the identity transform:

We could use the recover method:

Try {
  input.charAt(100)    // Some error-prone calculation
} recover { e =>
    println(e)         // log the exception
    '?'                // and provide a default value
} get

but recover produces a Try[T] (which is guaranteed to be a Success). That has to be unwrapped with a dangling get (which also needs need postFixOps in this style).

We could also use getOrElse, but this doesn't allow us to log the exception.

Try {
  "input".charAt(100) // Some error-prone calculation
} getOrElse { 
  // println(e)       // We don't have access to the exception and can't log it
  'a'                 // provide a default value.
}

What I would really like is an unwrap or recover++ method like

def unwrap[U >: T](pf: PartialFunction[Throwable, U]): U

that either unwraps the T from the Success or unwraps the Throwable from failure and transforms it to a U with the partial function.

The easiest way I can see to do that would be to wrap the recover/get pipeline in an extension method that I add to Try, but that also sounds like overkill.

Does anyone have a slick way to implement this behavior?

P.S. I found this related question that suggests that leans towards pattern matching, but I want to see if anything better has come around in the last 5 years - Try recover get vs Try match

like image 936
Brad Carter Avatar asked Jul 18 '26 08:07

Brad Carter


1 Answers

I've used the recover pattern to catch and log errors. You can also just re-throw the exception (or a different exception) from the recover block, like in this simple Json parsing code:

Try {
  (parse(json) \ "something").extractOrElse("default")
}.recover({
  case exception: Exception => throw new IllegalArgumentException(s"Invalid JSON: ${exception.getMessage}")
}).get
like image 188
Jeremy2048 Avatar answered Jul 19 '26 21:07

Jeremy2048



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!