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.