As I mentioned a few days ago, I've been hacking around in javac recently in an attempt to get it to implement some of the ideas in the
CICE and
ARM proposals. The idea being that having a prototype available may help to highlight which aspects of the proposals really work in practice, and which do not.
I've put an initial cut
here, which is based on the JRL licensed JDK codebase from 04-Dec-2007 (JDK 7 build 24). It hasn't had a great deal of testing, so don't expect it to be wonderfully stable at this stage. I'll attempt to fix any bugs that crop up however.
It's important to note that this initial prototype has been put together without consulting the authors of the two proposals, so I may well have misunderstood some of the ideas - apologies if so. I've also had to make a call on which aspects of the proposals to include, and which to exclude for now. I've opted for a pretty minimalist implementation to start with, and that pans out as follows:
CICECICE expressions, public local variables and implicitly final local variables should all be working. I've left out transient public locals and type inference.
At this stage, I also haven't provided any of the library additions or changes mentioned in section IV of the proposal.
Basically all of the examples in the CICE document should work (apart from those involving AbstractThreadLocal).
ARM blocksARM blocks can take one of two forms, both based on the
do keyword only for now. The first allows you to declare the resources' variables as part of the ARM block itself:
do (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest)) {
// ...
}
The second form is where the resources are provided as a list of expressions:
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest);
do (in, out) {
// ...
}
Currently, all resources must implement java.io.Closeable. As the ARM proposal points out, Closeable is probably not a good choice in the long run, but it's a starting point.
An ARM block will attempt to call close() on all the resources, in the reverse order that they were listed. In the first form of the block the variables are not final so it
is possible to reassign
in and
out to some other Input/OutputStream within the ARM block - the block will attempt to close whatever Closeables the variables refer to at the time the block ends. In the second form of the block, reassigning
in and
out has no effect.
In the first example, if
in or
out are set to null this effectively cancels the automatic closing of the variable in question, and does not cause a NullPointerException or any other runtime error. I don't know whether this is useful or not, as yet.
In the first form, it's possible to mark the variables as final. It's also possible to mark them as public, which is only really useful if reassignment should be allowed.
If exceptions are raised, whether by evaluating the variable initializers (in the first form), by executing the body of the block, or by the calls to close() at the end of the block, it should only ever be the first such exception which is ultimately thrown by the block, after it has attempted to close all the resources.
The proposal doesn't mention whether it should be possible to use 'break' statements within an ARM block so I haven't implemented that. I think it may be useful though - thoughts welcome.
Bug reports and the like can be sent to me directly at markmahieu at gmail dot com.