A
Alessio Stalla
It's generally lesser known, as many of the closure adherents don't
want to make do with a Java "closures lite" solution (which is
essentially what FCM is: basically a way to define a function in the
middle of a method, as opposed to a true closure that handles control
flow of the enclosing [1] method).Since when was that the "true" meaning of 'closure'? That's a genuine
question - i hadn't come across the idea of nonlocal control flow being
essential to closures before. Indeed, it seems to me like an incredibly
bad idea which definitely should not be in the language.
I suppose that FCM does provide full closures, strictly according to the
definition of closure. But then again, Java already has a limited form
of closures: inner classes, defined within methods, gain access to the
(final) local variables in scope.
This is roughly the story as I understand it:
It all begins, I think, with the try-finally construct. Whenever you
work with native resources, you typically need to open them and then
always close them, such that this becomes boilerplate:
SomeObject foo = /* get from somewhere */;
foo.open();
try {
// Magic foo operations
} finally {
foo.close();
}
The typical name for this is Automatic Resource Management (the ARM in
CICE+ARM). The idea is to be able to simplify that into:
with (foo.open()) {
// Magic foo operations
}
People then got the idea that it would be nice to be able to create
arbitrary control structures--the only other one I've seen that looked
remotely useful (indeed, the /only/ other I've seen at all) was some
sort of forEachInMap construct. This can of course be implemented with a
sufficiently-advanced closures framework, specifically one allowing
non-local control flow modification.
From my experience in another language (Common Lisp) that has had
closures from its inception, I think the association between closures
and ARMs (and control flow in general) is not what closures are all
about. Closures are simply functions that "close over" (capture) the
lexical environment they are defined in. In all effects closures in
Java should be like anonymous inner classes with a single method,
except that they should be able to modify the bindings they capture
(i.e., capture non-final variables as well). In fact, closures can be
used to implement simple message-passing OO systems with little
effort, so the analogy with classes holds.
In general, closures can be used for many things: callbacks, higher-
order functions (think Comparator), and, yes, ARMs. Apart from the
ugly syntax, introducing twists and complications in a simple concept
like closures just to make ARMs a little simpler to write is the main
mistake by the proponents of BGGA. For the record, I like the syntax
inspired by C function pointers.
Now there's something else that a lot of BGGA proponents seem to cite.
Something called "Tennent's Correspondence Principle" which I've
actually found very hard to track down. Apparently, it roughly states
that |expression| should be equivalent to |{ ==> expression }.invoke()|
(to use the BGGA syntax). The BGGA proponents cite that as the reasoning
behind having the non-local control flow, but it seems to be an open
question as to whether or not the guy actually meant to include the
effects of control flow statements in his principle.
I don't know where they took that principle from, and it seems silly
to apply it to everything. Definitely closures do *not* respect it in
other languages I know; e.g. a return inside a closure returns from
it, not from the enclosing function/method, and for a reason: doing
otherwise would severely limit the usefulness of passing around
closures and call them at a later time, when the defining method is no
longer being executed - which is the main reason for having closures!
It is ugly, but closures proponents would tell you that it's necessary
to tack closures onto the current language: it represents the ability to
use closures with classes not designed with them in mind.
Well, I gave up on BGGA after seeing a conversation to this effect:
"Well, of course { => return 42 } is the correct answer; why would
anyone think it should be { => return 42; }?" Even if that part is
completely eradicated from the final proposal, just the mere fact that
proponents didn't realize the pitfall in having the presence or lack of
the statement delimiter do two *completely* different things is enough
in my mind to banish it to the deepest flames of Hell for all eternity.
I completely agree!
-- Alessio