Feedback and comments on ARM proposal

Neal Gafter neal at gafter.com
Thu Mar 12 15:28:53 PDT 2009


I'd like to suggest a solution to the problem of adapting existing
APIs, based on experience with C#.

There is an existing type in Java's language support libraries that is
used in a one-shot way, but doesn't require explicit disposal. That is
java.util.Iterator. Some particular API may elect to provide a subtype
of Iterator that does require disposal. One can then use the proposed
resource-management statement to ensure its proper termination, but
one cannot then use the for-each loop, which works only on an
Iterable.

C# has both a for-each loop ("foreach") and a resource-management
statement ("using"). The C# equivalent to this proposal's Resource
interface is IDisposable, and C#'s close method is Dispose. Unlike the
present resource managment proposal, however, C#'s foreach loop
invokes the iterator's dispose method when the loop exits if the
iterator's type extends IDisposable. Were this proposal to take the
same approach for Java (that is, specify that the for-each statement
calls iterator.close() at the end of the loop if its type extends
Disposable), one could build an API to easily iterate over the lines
in a file, automatically closing the file when done:

for (String line : eachLine(fileName)) {
    System.out.println(s);
}

The implementation would begin something like this

interface DisposableIterable<E,X extends Exception> extends
Disposable, Iterable<E> {
    void close() throws X;
}
static DisposableIterable<String, IOException> eachLine(String
fileName) throws IOException {
    // implementation left as an exercise for the reader
}

There are some interesting aspects to the implementation. For example,
because Iterable's methods are not declared to throw IOException, such
exceptions must be handled before returning. This can arranged by
saving an IOException in the state of the DisposableIterable, and then
rethrowing it from the close method.

This mechanism can also be used to build concise adapters for other
types. Consider, for example, SWT's Resource class. As you may recall
SWT's Path class has a dispose method that releases the resource, but
the existing close method is used to complete a "closed path" by
adding a line back to the start of the path. Path can't be retrofitted
to implement the new Disposable interface, and therefore its
superclass, SWT's Resource abstract class, can't be retrofitted
either. Here is how to adapt SWT's Resource class to allow
auto-disposal:

static <T extends Resource> DisposableIterable<T,RuntimeException>
autoDispose(T t) {
    // implementation left as an exercise for the reader
}

The returned iterator would yield precisely one result, which is the
value passed in to the method. It would be used like this:

for (Path p : autoDispose(new Path(...))) {
    // use the path
}

This is a bit of a hack, as the for-each loop doesn't read quite right
for this use case, and the definite assignment rules are not ideal.
But it's better than anything else I've seen to address this issue
with the proposal.

If this approach is pursued, there remain some minor technical points
to resolve. For example, should the test for whether the Iterable
implements Disposable be a static test, performed at compile-time, or
a dynamic test, performed at runtime? Performing it at runtime may
allow more APIs to be retrofitted, as it is not always compatible to
change types in an API. However, existing compiled for-each loops do
not perform that test. This might not be a change that one could
compatibly add to a later release, as it would change the behavior of
existing code, so if this is worth considering it should be considered
now.



More information about the coin-dev mailing list