Compile-time closure conversion is at the heart of the proposal, and therefore the syntax as well as semantics of closures must indicate the right kind of conversion to the compiler:
A closure is converted to some object type at compile-time by a closure conversion.
According to the proposed spec, the object type a closure is converted to is a compatible interface: one with a single method that, in turn, is compatible with the closure. A method is compatible with a closure if, in essence, it has the same effect as the closure does:
Either:
The closure has no final expression and the method m has return type void; or
The closure has a final expression and there is an assignment conversion from its type to the return type of m; or
The body of the closure cannot complete normally.
... has the same number of arguments as the closure.
For each corresponding argument position in the argument lists, both argument types are the same.
Every exception type that can be thrown by the body of the closure is a subtype of some exception type in the throws clause of [the method].
Special provision is made for closures that do not return normally, such as when encountering an exception:
We add the non-instantiable type java.lang.Unreachable... Values of this type appear only at points in the program that are formally unreachable. This is necessary to allow transparency for closures that do not return normally. Unreachable is a subtype of every type (even primitive types).
Another common case are closures that return void. Gafter notes that,
The next version of the proposal will include in the closure conversion a provision allowing conversion of a closure that returns void to an interface type whose method returns java.lang.Void.
The reason for introducing Void has to do with the ability to better define control structures in closures while still allowing conversion in an unambiguous manner, according to Gafter's post. The problem is illustrated in snippets of an email conversation Gafter quotes:
We'd like programmers to be able to define their own control constructs. One thing that would make this easier would be if programmer-defined control constructs act like built-in ones for the purposes of handling reachability of statements... That's why we added the bottom type java.lang.Unreachable to the specification. But just having that isn't enough. Watch as I try to define a withLock method that is completion transparent.
First, ignoring reachability, the library writer might define
This achieves exception transparency, but not completion transparency. If the block returns a value, this would work:
<T, throws E> T withLock(Lock lock, {=>T throws E} block) throws E { ... }
This works because a closure that can't complete normally can be converted, via the closure conversion, to {=>Unreachable}...
Unfortunately[,] it isn't that simple. With these two methods, an invocation of withLock using a closure that can't complete normally can be an invocation of either of these methods. That's because the closure conversion can convert a closure that results in Unreachable to an interface whose method returns void. Since both are applicable, the compiler must select the most specific. Neither of these methods is more specific than the other ... so the invocation is ambiguous.
The proposed solution, according to Gafter, will:
Allow... to convert a closure that results in void to an interface whose method's return type is java.lang.Void. The generated code would naturally return a null value. Then the library writer would write only the second version, above, and it would work both for the void-returning case and the Unreachable-returning case.
What do you think of the current closures proposal? To what extent do you think it supports the level of ease-of-use that's the hallmark of closures in languages such as Ruby?
I was originally of the opinion that very short syntax, e.g. Ruby, was a good idea but having suggested an RFE (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6389769) and blogged (http://www.artima.com/forums/flat.jsp?forum=106&thread=182412) a couple of times, I kept getting feedback that the syntax from languages like Ruby wasn't Java. I came round to the view that you need a Java like syntax, otherwise you run the danger of ruining the language. In particular Java uses a standard structure of keyword ( list ) { block }, e.g. for, etc., it does not use a combination of symbols, e.g. extends instead of :. Therefore the proposed anonymous method declaration in the Gafter proposal, e.g. {int,Object=>float} will not be loved.
The Artima blog referenced above uses a Java like syntax and yet gives Clear, Consistent, and Concise Syntax.
> The Artima blog referenced above uses a Java like syntax > and yet gives Clear, Consistent, and Concise Syntax.
I prefer the {int,Object=>float} syntax. In overall the Gafter's proposal is much simpler, and at the same time much more expressive, than C3S. Rules of the Gafter's proposal have a purpose, they introduce semantically poweful constructs (in particular the non-local control flow constructs), and the minor cases of pure syntactic sugar have a taste (control invocation syntax). C3S is just a thin syntactic layer over the unchanged poor Java semantics, and it's close to syntactic ambiguity.
As far as I can see the only place that the Gafter proposal does something that C3S doesn't is with regard to break and continue. In C3S support for these statements is listed as an optional second stage in C3S whereas Gafter has them in his proposal from day one. If people really want them then include them in C3S, just go with the majority.