понедельник, 12 августа 2013 г.

Implementing try-with-resources in Xtend

Java 7 and C# provide a convenient syntax that ensures the correct use of Closeable (IDisposable) objects. In Java 7 it is called try-with-resources. Here is an example of its usage (Java code):

try (Reader reader = new FileReader("file.txt")) {
  // do something with reader
}

Xtend does not provide this feature. However, you can implement it easily:

class Using {
  def static <T extends Closeable, R> R using(T resource, (T) => R proc) {
    // This is kept for a case when a Throwable from close()
    // overwrites a throwable from try
    var Throwable mainThrowable = null

    try {
      return proc.apply(resource)
    } catch (Throwable t) {
      mainThrowable = t
      throw t
    } finally {
      if (mainThrowable == null) {
        resource.close
      } else {
        try {
          resource.close
        } catch (Throwable unused) {
          // ignore because mainThrowable is present
        }
      }
    }
  }
}

This is sometimes called a loan pattern which is widely used in Scala. I use using as a method name, because try is a reserved keyword in Java and Xtend. The following example shows how to use the using statement:

import static org.example.xtend.Using.*

val text = using(new FileReader('file.txt')) [
  val buf = CharBuffer::allocate(1024// this is just an example
  it.read(buf)
  buf.rewind
  buf.toString
]

println(text)

One can use it keyword to refer to a passed instance of Closeable.
The nice feature is that using can also return a value. So, "Everything is an expression" principle works here as well.