Feedback and comments on ARM proposal (original) (raw)

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 { 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 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