Automatic Resource Management

Reinier Zwitserloot reinier at zwitserloot.com
Mon Apr 13 15:21:44 PDT 2009


Allen, you haven't answered any of the questions about using an  
annotation, even if we forget for a moment that annotations aren't  
supposed to be used for this in the first place:

1. Do @Disposable annotations inherit (if not, the proposal really  
stinks, so I'll assume it does, which leads to):

2. What if 1 object has multiple @Disposable annotations? Call them  
all? That's rather a lot of exceptions that could occur - do we stop  
calling them all once one of them throws an exception, or keep going?

3. What if the close() method doesn't actually exist? Whose job is it  
to generate a compiler error?

4. Should @Disposable be sorted out at runtime, or at compiletime? In  
other words, if I have a variable typed 'Foobar', named 'foobar', and  
I try() on this, should I just call all the close methods that I can  
find when chasing down the Disposable annotations of Foobar, or should  
I ask for foobar's actual type (foobar.getClass()) and work with that  
instead? If we go with the compile-time option, then won't this cause  
some fairly serious confusion and possible resource leakage?


These are all serious issues, and while you could pick a solution for  
them all, and document this extensively, your average java programming  
just doesn't read all of the JLS - in other words, language changes  
should be as self-sensible as possible. Josh's proposal may not work  
for every existing class, but it has clear and obvious answers for ALL  
of those issues. In case people are wondering what they are, here they  
briefly follow:

1. interfaces inherit already (if your superclass implements X, so do  
you - you can't undo this), so the answer is obvious: Yes.

2. There's only one method, so even if the Disposable interface is  
implemented many times over, it makes absolutely no difference:  
close() willbe called, and that's the only method.

3. It's already an error to not implement an abstract method, so  
that's easy.

4. This situation cannot occur; either the compile-time type is a  
Disposable, and thus the close() method is called, or it isn't, and  
the try() form is not even legal. You could cast your object to a  
Disposable, and this would work, but then the method to call is also  
obvious (close), as is the error when the object isn't actually  
disposable at all (ClassCastException). None of these things even need  
to be specified in Josh's ARM proposal, because these are the rules  
that already apply to implementing interfaces.



I hope this mail summarizes the major issues (aside from the notion  
that annotations should not affect compilation like this) with using  
an annotation. Before initiating too much discussion on these  
problems, please review the (many, many) emails that have already been  
spent on the topic, lest we just rehash the same arguments over and  
over.


A telling point: NOBODY submitted an official annotation based ARM  
proposal for coin (at least none that had a snowball's chance of being  
accepted - i.e. having enough detail to update javac and covering  
every open issue like the ones stated above).


  --Reinier Zwitserloot



On Apr 13, 2009, at 18:26, Allen, Chris wrote:

> I've looked at Automatic Resource Management proposal, and written  
> this
> email and then sat on it for several days, and it seems that the  
> current
> proposal, adding a Disposable interface, is arbitrarily restrictive  
> and
> that by using an attribute combined with a signature matching we could
> get better bang for our buck.
>
> We already use annotations to describe classes such as persistable or
> deprecated, why not as a resource?  I've read the objections on this
> list to using an annotation, and the interface proposal does list  
> common
> resources such as Streams and SQL constructs, but while the interface
> would probably be the preferred way to add this if we were designing  
> the
> language from scratch, we already have a huge collection of code out
> there where a typical resource pattern is already used - but where
> close() is not the disposal method.  People have pointed out locks for
> instance, but were told that locks were beyond the scope of this small
> change.
>
> Why?
>
> We're looking to make a small change to Java that will make source  
> code
> easier to read, write and maintain while making the new constructs  
> easy
> to recognize.
>
> The try() syntax that's been proposed seems to meet that criteria,
> although I would argue against multiple resources being opened in one
> try statement (that's not easy to read) and propose this two-step
> processes to find the method called to dispose the target of the try:
>
> 1. If the instance's class or one of it parent classes or interfaces  
> has
> an attribute of @Disposable the method named in the attributes "value"
> value is the name of the method to call.  The default value for  
> "value"
> is "close".
>
> So:
>
>    @Disposable("close")
>    public abstract java.io.InputStream { ...
>
>    or
>
>    @Disposable
>    public abstract java.io.InputStream { ...
>
>    Would call close() to dispose of an InputStream.
>
> where as
>
>    @Disposable("unlock")
>   public interface java.util.concurrent.locks.Lock { ...
>
>    Would call unlock() to dispose of a Lock.
>
> 2. If the instance's class and all of it's parent classes and  
> interfaces
> has no @Disposable attribute, and a instance method matching this
> signature 'public void close()' exists, regardless of exception  
> thrown,
> it can also be used as a resource.
>
> So:
>
> public void MyClass {
>
>   public void close() throws MyOwnException;
>
> }
>
> Could still be used even without the @Disposable attribute even if  
> it's
> compiled in some jar file that I don't have the source for.
>
> I understand the parallelism that we'd like to achieve with the
> interface decisions made with Iterator.  There a very small change was
> introduced in by the addition of an interface, and voila for-each  
> loops.
> But we're talking a much broader range of classes here, including
> various 3rd party binaries that have classes that are resources.  With
> Iterator there was a very small set of classes affected - mainly
> Collection and arrays, but resources could be database connections,  
> text
> files, locks, threads, servers, memory, scripting engine or any number
> of other things.
>
> Besides, the Disposable interface ends up basically being a marker
> interface.  Since no one is going to go around throwing Exception from
> the Disposable interface, you're always going to have to narrow the  
> list
> of thrown exceptions to something like java.sql.ResultSet so that you
> can deal with SQLException instead.  I can't think of a situation  
> where
> you're going to be using a Disposable objects directly (other than
> perhaps some resource manager).  So Disposable degrades into a marker
> interface, and when I think marker interface, I squirm a bit.
>
> Here's how the annotation might be described.
>
> @Documented
> @Retention(RetentionPolicy.CLASS)
> @Target({ElementType.TYPE})
> public @interface java.lang.Disposable {
>  String value() default "close";
> }
>
> The compiler simply picks the correct dispose method (or methods if
> parent classes define additional dispose methods) at compile time so
> this has no effect on runtime speed.  Remember, the whole idea is to
> change:
>
> A a = new A();
> try {
>    B b = new B();
>    try {
>        a.doSomethingTo(b);
>    }
>    finally {
>        b.dispose();
>    }
> }
> finally {
>   a.dispose();
> }
>
> into an easier to read, easier to understand, easier to write:
>
> try (A a = new A()) {
>    try (B b = new B()) {
>        a.doSomethingTo(b);
>    }
> }
>
> Why should it be limited to classes that have a close() method and  
> have
> to have a Disposable interface, too?
>
> As an aside, one of the ideas that needs to be promoted in any of  
> these
> proposals, is the idea that the exception thrown during the main  
> life of
> the resource receives priority over any exception thrown by the  
> dispose
> method(s).  This is a fantastic idea, but sounds fishy at first  
> glance.
> By responsibly closing your resource even during some catastrophic  
> event
> you can actually erase what the catastrophic event was and waste many
> hours of debugging.  This idea needs to be made clear: the proposal
> doesn't not hide the dispose exception, just doesn't favor it when
> competing with the primary exception.
>
> We already have a lot of JDK code out there and a good portion of it
> does not use close() as it's dispose method.  Adding the Dispose
> interface to so many classes seems to break the "small change  
> rule".  An
> annotation combined with a backup method signature match, covers many
> more resources than the interface proposal and is more compatible with
> the various types of resources already in use.
>
> P.S. Apologies to any people who's toes I've stepped on, some of the
> ideas I've stated here have been stated by others, too.
>
> -Chris Allen
>
> -------------------------------------------------------------------------------------------
> ***National City made the following annotations
> -------------------------------------------------------------------------------------------
> This communication is a confidential and proprietary business  
> communication.
> It is intended solely for the use of the designated recipient(s).   
> If this
> communication is received in error, please contact the sender and  
> delete
> this communication.
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
>




More information about the coin-dev mailing list