Automatic Resource Management, V.2

Paul Martin paul.martin at gmail.com
Mon Apr 20 12:59:04 PDT 2009


Hi,

>> > *5. Some failures of the **close** method can be safely ignored (e.g.,
>> ...
>> > these exceptions are ignored. If you feel you must ignore them, there is
>> > a
>> > workaround, but it isn't pretty:
>>
>> Could you use a decorator to simplify the code a little, such as:
>>
>> public class HideAutoCloseableExceptionsAdapter implements AutoCloseable {
>>        private final AutoCloseable delegate;
>>        public HideAutoCloseableExceptionsAdapter(AutoCloseable delegate) {
>>                this.delegate = delegate;
>>        }
>>        @Override
>>        public void close() {
>>                try {
>>                        delegate.close();
>>                } catch (Exception e) {
>>                        // Do nothing
>>                }
>>        }
>> }
>>
>> static void copy(String src, String dest) throws IOException {
>>       InputStream in = new FileInputStream(src);
>>       try (new HideAutoCloseableExceptionsAdapter(in)) {
>>           try(OutputStream out = new FileOutputStream(dest)) {
>>               byte[] buf = new byte[8192];
>>               int n;
>>               while ((n = in.read(buf)) >= 0)
>>                   out.write(buf, 0, n);
>>           }
>>       }
>>   }
>> }
>
> Yes; you could do that.  Of course you'd have to write a separate decorator
> for every such type.  But it's worth mentioning that in the FAQ, and I will
> do so.

Just to clarify, I think that "HideAutoCloseableExceptionsAdapter"
should work with any AutoCloseable (as long as the decorated object is
declared before the try), so you could use that to address Neal
Gafter's point 5: "*5. Some failures of the **close** method can be
safely ignored (e.g.,closing a file that was open for read). Does the
construct provide for this?".  Simply using a standard decorator would
seem to be a reasonable solution (since ignoring close exceptions
would normally be done on a usage case-by-case basis).  Giving the
adapter a better name, such as "IgnoreCloseExceptionAdapter" might
help, or even a static factory method such as AutoCloseable
autocloseQuietly(AutoCloseable delegate).

Also, one question from: http://docs.google.com/Doc?id=ddv8ts74_1d7tz65fd

> java.util.Iterator&AutoDisposable:
> "We can learn from C# here, and avoid the same mistake that C# avoided.  The simple solution is to make the for-each loop dispose the iterator if it implements AutoDisposable, as C# does. The point, in part, is to make the proposed construct not just useful in code that already exists (criterion [2]), but useful in code yet to be written."

How can the compiler do this (determine whether an Iterable is also
AutoDisposable)?  An Iterable interface passed to the for-each loop
might not be defined as AutoDisposable, but its runtime implementation
might be.  I don't see how this can be statically determined by the
compiler, and I wouldn't think that we would want the type of each
Iterable to be checked at runtime to determine whether it also
implements AutoDisposable (in case some objects are AutoDisposable and
other objects are not).  The alternative of using the static type of
the interface to extend AutoDisposable would also seem to be fragile -
AutoDisposable objects would then sometimes not get closed by for-each
loops. ResourceSpecifications are known to be AutoDisposable for ARM,
so the problem doesn't exist there (the statically-determined
interface/class used must implement AutoDisposable).

One further comment about suppressed exceptions: I would suspect that
in many cases that the suppressed exception may indeed represent the
original error (for example out of space when writing to a file), but
the exception caused by the close represents later information (e.g.
none of the previous writes to the were actually flushed to the disk).
 Perhaps exceptions thrown by close should be structured so that
sufficient information is available in the exception itself to handle
the error, so that suppressed exceptions should not often need to be
consulted directly.

Also, I haven't seen much discussion comparing similar implementations
in other languages (but may have missed it).  From what I can see (but
I haven't actually used either), .Net ignores suppressed exceptions
and uses 'using (resource decls) { ... }' without optional catch and
finally blocks.  Python's 'with' statement seems to allow both
'__enter__' and '__exit__' methods (without a common interface), but
again without suppressed exceptions.  I can't see any advantages for
either over this ARM proposal.

Finally, have you considered a syntax such as:  using
(*ResourceDeclarations*) *statement*  ?

Then I think that you could access the variables in catch blocks
before the close method is called (though admittedly this really only
saves a single level of nesting):

using (MyResource var) try {
    ...
} catch (MyException e) {
   // caught before AutoCloseable.close();
   var.xxx();
}

as well as

try using (MyResource var) {
    ...
} catch (MyException e) {
   // caught after AutoCloseable.close();
   // so can't access var
}

Regards,

Paul



More information about the coin-dev mailing list