try-with-resources for Scala

Since it’s release about a year ago, a lot of buzzing has been going on about new language features in Java 7 - least of which about the new try-with-resources statement. Here’s how you can implement it within Scala.

In case you don’t know, let’s quickly explain how the try-with-resources statement works. Here’s a trivial example:

try (PrintWriter out = new PrintWriter(new File("file"))) {
    out.println("Hello world!\n");
}

Doesn’t look like much, but this statement provides two features:

  1. out.close() will be called as soon as the try-block is left, even if the block terminates with a Throwable.
  2. In case the try-block terminates with a throwable x and the call to close() terminates with another throwable y, then the throwable y gets added to the throwable x as a suppressed throwable by calling x.addSuppressed(y).

Suppressed exceptions will be marked as such whenever a stack trace is printed via Throwable.printStackTrace(), so they leave a trace for you to follow.

When the compiler sees the previous statement, it will effectively rewrite it to (see The Java Language Specification, Java SE 7 Edition, section 14.20.3.1):

{
    final PrintWriter out = new PrintWriter(new File("file"));
    Throwable t = null;
    try {
        out.println("Hello world!\n");
    } catch (Throwable x) {
        t = x;
        throw x;
    } finally {
        if (out != null) {
            if (t != null) {
                try {
                    out.close();
                } catch (Throwable y) {
                    x.addSuppressed(y);
                }
            } else {
                out.close();
            }
        }
    }
}

You could actually think of the try-with-resources statement as an implementation of the loan pattern: The resource within the parenthesis of the try-statement gets “loaned” to the try-block for processing, after which it gets automatically “reclaimed” by calling AutoCloseable.close().

Scala doesn’t have a try-with-resources statement, but thanks to closures, you can easily implement it using the following code:

import java.io._

class Loan[A <: AutoCloseable](resource: A) {
  def to[B](block: A => B) = {
    var t: Throwable = null
    try {
      block(resource)
    } catch {
      case x => t = x; throw x
    } finally {
      if (resource != null) {
        if (t != null) {
          try {
            resource.close()
          } catch {
            case y => t.addSuppressed(y)
          }
        } else {
          resource.close()
        }
      }
    }
  }
}

object Loan {
  def loan[A <: AutoCloseable](resource: A) = new Loan(resource)
}

As you can see, this is an exact implementation of Java’s try-with-resources statement for Scala. Getting back to the initial example, you can now translate it to Scala as follows:

import java.io._
import Loan._

loan (new PrintWriter(new File("file"))) to (_ println "Hello world!\n")

See how Scala’s DSL support makes a nicely readable loan-pattern statement? Now you don’t need to copy-paste this code if you don’t mind adding a dependency to your Maven build. Just add the following dependency:

<dependency>
    <groupId>net.java.truecommons</groupId>
    <artifactId>truecommons-io</artifactId>
    <version>1.0</version>
</dependency>

or directly download the JAR from Maven Central and explore its other features. Source code and Javadoc are available on Maven Central, too.

Enjoy!