I was upgrading one of my open-source projects (TableParser) to Scala 2.13 and I realized that I could now use the new "Using" resource management utility.

But, it seems they missed a necessary signature. Let's review:

The basic signature for normal (single-resource use) is this *apply* method (I've used a context bound to save a bit of space, and I also renamed the first parameter to *r*):

def apply[R : Releasable, A](r: => R)(f: (R) => A): Try[A]

` = Try { Using.resource(r)(f) }`

As you can see, it invokes the other single-resource signature *resource*:

def resource[R : Releasable, A](r: R)(f: (R) => A): A

The difference between these signatures is somewhat subtle: *apply* returns a *Try[A] *whereas *resource* returns *A*. But, there's another, more subtle yet more significant difference: the *r* parameter in *apply* is call-by-name, whereas in *resource*, it's call-by-value. This implies that, if an exception is thrown while evaluating *r *for* resource*, it will indeed be thrown and not wrapped in a *Failure*. So, the *resource* signature is not suitable if there's a possibility of an exception being thrown while evaluating the *r* parameter.

If that's the case, then you must use the *apply* signature. However, suppose that your type *A* is of the form *Try[X]*, then the result type will be *Try[Try[X]]*. That's a bit ugly.

What is needed is a method such as the following (this signature is to *apply*, as *flatMap* is to *map*):

def safeResource[R: Releasable, A](resource: => R)(f: R => Try[A]): Try[A] = Using(resource)(f).flatten

An alternative expression for the body of this method would be the following:

try { Using.resource(resource)(f) } catch { case NonFatal(e) => Failure(e) }

You could, of course, add the *flatten* method call yourself, but that's not the most elegant. So, I think it would be nice to have this signature added to the *Using* object in the Scala library.

## No comments:

## Post a Comment