Help us brainstorm closure syntax.

114 views
Skip to first unread message

Reinier Zwitserloot

unread,
Oct 1, 2009, 2:07:45 PM10/1/09
to Project Lombok
So, no promises, but we _really_ want to add closures to lombok,
partly because quite a few folks keep suggesting that lombok can't
handle such a complex beast. But, if we do, we want to do it right.
The fatal flaw in FCM and CICE is the lack of transparency (so, you
couldn't use it roll your own 'synchronized', for example, as in both
FCM and CICE, inside the closure, the meanings of 'throw', 'return',
'break', and 'continue' all change, which does not happen for e.g. a
synchronized block. In a foreach loop, only the meaning of 'break' and
'continue' should be changing, etcetera. BGGA's flaw is its ridiculous
complexity, as well as its insistence of having structural types,
which just isn't java, and has nothing to do with closures.

So, the closure proposal we're working on has transparency - but only
where its useful, not as a general rule like BGGA - but no structural
types. Every closure you write ends up being an implementation of a
known and explicit type. Such as Comparator.


We've got most of it worked out, except for the syntax. The issues
we're wrestling with:

- How do you specify the parameter lists of the closure, and how do
you separate the parameters from the actual code?
- How do you return from the closure itself? If we're going to stick
to transparency, "return" itself cannot change meaning, and therefore
would return from the method that you wrote your closure inside of,
and not from the closure itself. Some closures return values, like,
say, Comparator.
- How do we avoid the passing of a closure straight to a method
looking like a mess of braces, parentheses, and brackets?
BGGA solves these with:

- {paramType paramName, paramType2 paramName2 => code}
- last expression in the block, that does not end in a semicolon.
- if a method call ends in a closure parameter, you may move the
closure out. Along with a complex set of rules to make this work in
light of method overloading.

So, in BGGA:

Collections.sort(stringList) { String a, String b => Integer.valueOf
(a.length()).compareTo(b.length()) };


Here's a rough draft of what we're looking at:

Collections.sort(stringList, #(String a, String b) {
return short Integer.valueOf(a.length()).compareTo(b.length());
});

Couple of things to note:

- "short" is of course a keyword, which is why that syntax has a
snowballs chance of meshing with the existing java grammar.
- unlike BGGA's syntax, there's a fairly natural place where you can
insert a line-break (where would you linebreak the BGGA sample? Before
the paramlist, or right after the arrow operator?
- with this proposed syntax, stuffing it all on one line looks pretty
bad, because of the way it would end: "));});" - there's that mess of
braces and brackets I was talking about.
- unlike BGGA syntax, it's easy to short return in the middle of your
closure. In BGGA the only way to short return is via the last
statement in the closure block.
- You may replace the # with Comparator if you feel that's more
readable. Without #, a suitable type is inferred. Either way it must
be a SAM type (an abstract class or interface with exactly 1 method
that is abstract. all methods in interfaces are abstract - so with
interfaces, it can only have 1 method).


Half the people who don't like BGGA primarily complain about syntax,
so clearly its an important aspect of any closure proposal. What kind
of syntax do you guys like?

Some inspiration:

Ruby-style closure syntax:

{ |String a, String b| Integer.valueOf(a.length()).compareTo(b.length
()) }

Python-style:

No real syntax (well, there's lambda, but, too ugly for words), but
you can define methods in methods (something we'd like to add at some
point), and you can reference methods. So, you'd get something like
(inside a java method!):

int compareByLength(String a, String b) {
return Integer.valueOf(a.length()).compareTo(b.length());
}

Collections.sort(stringList, #compareByLength);

jpp

unread,
Oct 1, 2009, 4:18:41 PM10/1/09
to Project Lombok
My two cents:

— I have no problem with the end in "));});" with the proposed syntax;
on the contrary, other syntaxes where the last semicolon is suppressed
are less natural to read when written on two lines. The proposed
syntax is more natural—and anyway, it looks to me like we're all more
likely to have a line break somewhere for all but the most trivial
closures anyway, so it makes it all the more readable. (I'd hate
something like "=>", which would remind me of Ada...)
— "return short" looks too strange to me. I'd understand it as either
a late specification of the return type, or some kind of funny cast of
the return value. What about "return private"?
— Replacing "#" with "Comparator" wouldn't look natural. To C/C++
guys, it looks like the closure is returning a Comparator; to the Java
guys, it looks like we're defining a Comparator(String,String)
function/constructor, somehow. We're actually implementing a method.
Why not write the name of the method being implemented instead, e.g.
"compareTo"? Or maybe "Comparator.compareTo", if we want to specify a
type. On another detail: closures were recently introduced by Apple to
C/Objective-C with a syntax where the return type is specified and
where "^" is used instead of "#". Could something like this be used?
Collections.sort(stringList, ^(String a, String b) {
return private Integer.valueOf(a.length()).compareTo(b.length());
});
Alternatively, as we could suspect that "private returning" would be
much more common than returning from the enclosing method from within
the closure, we could trade off a bit of transparency, let "return"
return from the closure (after all, it's still a function, with a body–
a plain "return" seems natural to Java programmers), and introduce
"return public" or "return super" or, my favorite, "break return", for
returning from the enclosing method. "break return" seems descriptive
to me because "break" can be interpreted as making control flow jump
outside the containing loop/block/closure, and then the subsequent
"return" would be forwarded to the enclosing method.
(assuming all this new syntax can be parsed, of course...)

Roel Spilker

unread,
Oct 1, 2009, 6:59:56 PM10/1/09
to Project Lombok
To distinguish between the two types of "return", another idea is to,
inside a closure, never allow just "return". You have to explicitly
state what you mean. There is one exception. In shorthand form, where
the content of your closure is just one expression, that will be the
"value" if the closure.

The proposal is to use "long return" and "short return" for
respectively returning from the defining method or returning a value
from the closure.

If you combine that with a pipe-syntax, the code would look something
like this:

// There might be some very long names here...
List<String> names = Arrays.asList("Moe", "Larry", "Curly");
Collections.sort(names, |String a, String b| {
if (a.length() == b.length()) {
short return a.compareToIgnoreCase(b);
}
short return a.length() > b.length() ? 1 : -1;
});


In shorthand, it would look like this:

// All names are less than 100 characters
List<String> names = Arrays.asList("Moe", "Larry", "Curly");
Collections.sort(names, |String a, String b| a.length() - b.length
(););

Reinier Zwitserloot

unread,
Oct 2, 2009, 4:34:17 AM10/2/09
to Project Lombok
One correction: In the shorthand form (just 1 expression), we're
talking about an expression and not a block, so the expression would
not end in a semicolon, just like any other java expression does not
end in a semi-colon. So, that last example looks like:

Collections.sort(names, |String a, String b| a.length() - b.length());

An issue with this syntax is: What happens with empty parameter lists?
Force the use of a double-pipe? Allow leaving them out, effectively
creating auto-boxed lazy evaluators, like scala has? You could write:


Logger.getInstance().log(Level.FINEST, toString());

and, presuming this Logger framework only had one 'log' method:

public interface LogMessageProducer { String getLogMessage(); }
public void log(Level level, LogMessageProducer producer) {}

then this closure proposal would declare that the way to compile this
is to turn "toString()" into a closure. With the nice advantage that,
if toString() is expensive, and the logger is configured to simply
ignore Level.FINEST, it would never even be called.


Is that too much magic for a java proposal? The easy way to fix it is
to say that the bars are never optional. Then you'd write:

Logger.getInstance().log(Level.FINEST, || toString());

which is very consistent, easy to parse, visually mostly obvious
(though it does look a little bit like logical or), but it looks a bit
ugly to me, and it's not a normal expression - you would not be
allowed to cast it. After all:

(SomeType) || someExpression


is ambiguous; is that a closure that is being cast to SomeType, or is
that a variable named "SomeType", guarded with useless but legal
parentheses, logical-orred to the expression on the right?


NB: jpp: I don't see how ^ is any improvement; it's uglier than the
bars, has less precedent (in that | is used by active-something-or-
other and ruby, ^ is only used, recently, by an extremely niche
language*), it's just as awkward precedence wise (| is binary or, ||
is logical or. ^ is xor). I don't see how 'private' and 'public' bear
any relation to the notion of returning from the inner method or
returning from the outer method, which could easily also be a private
method. 'short' and 'long', while unrelated to those types, at least
do bear a relation to the english names for the return styles. While
replacing # with "Comparator" may not look natural to you, replacing
it with the method name is useless; while you can easily infer the 1
method name in a SAM type given the SAM type name (e.g. it's easy to
go from "Comparator" to "compareTo"), you cannot go from a method name
to the SAM type; in other words, the name "compareTo" is useless. The
only thing it could help with is a sanity check: If the inferencer
determines you must be wanting to create a Comparator here, then it
can doublecheck that if you used a name instead of a #, that it is, in
fact, "compareTo". This is a lot less powerful as you couldn't use it
to be explicit when the inferencer can't fix it for you. The thing is,
though, you *ARE* creating a Comparator object there, which is why
this syntax is also used in the CICE proposal.


Keep the feedback coming. Some alternative ideas to address your
issues:

- instead of 'short return' and 'long return', we could make 'inner
return' and 'outer return'. This would be harder to make work with the
parser, as 'inner' and 'outer' aren't keywords. "break return" can
work, but Roel and I are pretty much convinced that, due to the
confusion between these 2 ideas, that just a plain "return" should
ALWAYS be marked as: Be more specific! - so if 'break return' is the
outer return, what would be the inner return? "continue return"? That
makes no sense.

- Comparator.compareTo should certainly be legal.

- I'm shooting down every syntax we're coming up with that includes
anything resembling an arrow :P

*) Objective C is nice. A lot nicer than C++. It's also used quite a
bit, but it's only used in very specific circumstances. If you're not
writing a mac or iPhone app, the odds you're building it in ObjectiveC
are effectively zero. Hence: niche language.

jpp

unread,
Oct 2, 2009, 8:26:14 AM10/2/09
to Project Lombok
The bar syntax doesn't feel much like Java… Just out of curiosity:
what would prevent the use of regular parentheses?

I'd be against the use of auto-boxing for these closures, as it's not
obvious anymore what an expression like a.length() - b.length() would
do—this would depend on the context, and thus be confusing. Then
again, || doesn't look too good either. Why not "()"? Or, with your
initial proposal, "#()"?

(You've probably noticed that I know very little of language design;
I'm just speaking from the programmer's point of view.)

I agree that adding "compareTo" is useless from the compiler's point
of view—but I certainly improves readability: the programmer really
knows he's implementing compareTo().

"short return" and "long return" look better than "return short" or
"return long". But I would still argue that return, break, throw etc.
should act on the inner method. We know we're implementing a method,
so we expect "return" to return from this method. Just like in a
nested loop, "break" only breaks out of the innermost loop, and you
have to add labels to break out of anything else. And what about throw—
you probably want to be able to throw in the closure without throwing
in the outer method as well. Would you have "long throw", "short
throw" as well?

Another argument for avoiding to introduce a mandatory short and long
keyword before return is that it becomes easier to refactor existing
code, simply copying and pasting. It feels immediately familiar to
current Java programmers.

What I'd favor instead of an "outer return" is a syntax closer to what
Java already does when you have to "specify" a "this" or a "super":
you qualify it with the name of a class, or with an expression. Maybe
we could have "return" return from the closure, and
"enclosingMethod.return" return from the enclosing method? Same for
throw. What about it? This would be similar to the "break return"
idea, but more descriptive, readable, and inline with other parts of
the language syntax.

v6ak

unread,
Oct 2, 2009, 9:28:51 AM10/2/09
to Project Lombok
On Oct 2, 10:34 am, Reinier Zwitserloot <reini...@gmail.com> wrote:
> Logger.getInstance().log(Level.FINEST, || toString());

Well, you can write:
Logger.getInstance().log(Level.FINEST, | | toString());
I don't think that it is allowed to add whitespace into an operator.
However, I agree that somebody maybe don't know how to solve ||. It
can be magic for somebody.

>return short
I don't understand why is neccessary to write return type.

Groovy syntax is IMHO really nice, see http://groovy.codehaus.org/Closures
.
For example: You have a closure like {it.doSomething()} and you are
passing it to a method. You have to detect closure type by matching
*exatcly* one method. Then you have to detect name and type of
parameter it. (Where is the name from? If it was from interface's
method argument, it would be really ugly because of many ways to break
it.)

Reinier Zwitserloot

unread,
Oct 2, 2009, 9:42:40 AM10/2/09
to Project Lombok
Yeah, the bars are borderline ugly, though I'm not going to go as far
as calling them "un-java-like". Java has no clear semantics for
symbolism; most languages don't, with the exception of lisp.

I doubt that parens are going to be possible given the current state
of the java grammar. Too many things parens could be: cast,
algorithmic parens, or a closure. Too much ambiguity; even if it was
possible to make a grammar that can handle all those cases, then
making a single typo will likely through off the grammar and result in
a mystifying syntax error message. Bad.

With the hash, the grammar is of course easily adjustable, as the hash
symbol right now has no meaning whatsoever in java. The mean nicety of
the bars is avoiding paren-soup. I'm also of the opinion that it *IS*
unjava-like for the expression shortcut syntax if the paramlist works
via #():

Collections.sort(myList, #(String a, String b) a.length() - b.length
());

That just looks downright weird to me. We'd have to get rid of the
expression shortcut, so you'd have to write that out as:

Collections.sort(myList, #(String a, String b) {
short return a.length() - b.length();
});


Perhaps that's a good thing. Still, for a bunch of neat closure
tricks, its nice that you can shove expressions quickly into closures.
For example, if you want to fold a list of integers into a single
integer via plus:

List<Integer> myList = [1, 2, 3, 4, 5]; //this is (probably) going to
be legal in java7. Joy.
int addEachInt = Folding.left(myList, 0, |int a, int b| a + b);

In the alternate syntax:

List<Integer> myList = [1, 2, 3, 4, 5]; //this is (probably) going to
be legal in java7. Joy.
int addEachInt = Folding.left(myList, 0, #(int a, int b) {
short return a + b;
});


You know, the more I look at it, the more I'm starting to see your
point. The latter sample, while longer and probably somewhat less
natural feeling to people who are used to e.g. scala, does feel
fundamentally more java like. Somehow. Can't quite put my finger on
why just yet.



There's no long throw, short throw, long break, and short break. The
thing about all of those is that they are scope bound. They ALREADY
exist in a universe where their meaning is strictly dependent on their
scope. The fact that they are legal in closures therefore changes
nothing - it's just another scope level. Return on the other hand, in
current java syntax, is *NOT* related to scope. It will bust out of
whatever scope you're in until the method level, and as you can't nest
methods in java, there will always be 1, and exactly 1, method to
return out of. With closures this changes; there are now at least 2
methods you could be targeting.

And hence the problem: People are already used to 'break' and
'continue' busting out of the nearest loop-like construct, unless you
use labels. This isn't true for return statements.

We have discussed both labelled returns and type-specified returns
before. It might work as an alternative, but I (and probably Roel, if
our last chat on this topic is any indication) feel pretty strongly
that a vanilla "return" should always be a syntax error inside a
closure.

The big problem, then, with using type names, is that part of the
closure spec we're working on doesn't force you to even know what the
type name is; it's something you can ask your IDE if you want, but you
don't need to explicitly know it. So, you'd have to write:

Collections.sort(myList, #(String a, String b) {
Comparator.return a.length() - b.length();
}

note how Comparator snuck in there. Also, as this is more method-
related than type related, we'd really have to use method names:

public void test() {
Collections.sort(myList, #(String a, String b) {
if (a.length() == 0) test.return 10; //returns from test
method
compareTo.return a.length() - b.length();
}
}


Not sure this is really such an improvement over 'short return' and
'long return'. It's an idea though. I'll have to think about this a
bit more. Though, with the need to remember the method name, the
argument for supporting the single expression becomes more important
than ever before.

Reinier Zwitserloot

unread,
Oct 2, 2009, 9:47:35 AM10/2/09
to Project Lombok
v6ak:

I think you can actually stick whitespace in between, but
nevertheless, "| |" (with the space) is not going to be confused for a
logical or operator anytime soon, so it's nice that that style can be
maintained as a convention. Obviously closures are going to look like
magic to those who don't know what they are. That's not avoidable.


That 'short' in 'return short' (though we're all favouring "short
return" at this point) is NOT a reference to the 'short' type. It's a
reference to the english word 'short', as in 'nearby', as in: return
from the nearest method scope. The only other return statement would
be 'long return', which is a reference to the english word 'long', as
in 'far away', as in: return from the outer method scope.

On Oct 2, 3:28 pm, v6ak <v...@volny.cz> wrote:
> On Oct 2, 10:34 am, Reinier Zwitserloot <reini...@gmail.com> wrote:
>
> > Logger.getInstance().log(Level.FINEST, || toString());
>
> Well, you can write:
> Logger.getInstance().log(Level.FINEST, | | toString());
> I don't think that it is allowed to add whitespace into an operator.
> However, I agree that somebody maybe don't know how to solve ||. It
> can be magic for somebody.
>
> >return short
>
> I don't understand why is neccessary to write return type.
>
> Groovy syntax is IMHO really nice, seehttp://groovy.codehaus.org/Closures

Marvin Greenberg

unread,
Oct 2, 2009, 10:20:12 AM10/2/09
to project...@googlegroups.com
On 10/2/09 4:34 AM, Reinier Zwitserloot wrote:
> One correction: In the shorthand form (just 1 expression), we're
> talking about an expression and not a block, so the expression would
> not end in a semicolon, just like any other java expression does not
> end in a semi-colon. So, that last example looks like:
>
> Collections.sort(names, |String a, String b| a.length() - b.length());
>

In your comment about python syntax for closures, you said

> ..., but you can define methods in methods (something we'd like to add at some
> point)


So why not do it that way and get both closures and the syntax to define
methods. Of course, everyone will WANT inline closures so you still need
syntax for that.

int compareTo |String a,String b| { return a.length() - b.length(); } // Defines compareTo
int compareTo |String a,String b| { a.length() - b.length() } // syntactic sugar
Method compareTo = |String a,String b| { return a.length() - b.length(); } // Similar
Collections.sort(names, |String a,String b| { a.length() - b.length() } )
Collections.sort(names, compareTo );

My desire would be to introduce less new syntax and keep the introduced
syntax consistent. One of the big problems (I have) with scala is all the different
syntax in different contexts that accomplish effectively the same thing.

I guess my usage of closures has been fairly ordinary so I don't really see
the problem of redefining "return" in the closure. But assuming you need a way
for a closure to return from its calling context, I'd rather make THAT
explicit. How about "return return;" Or, jpp's "break return;" Since most people
using closures will use them more conventionally, I'd hate to have an errant "return"
typo do something unexpected.

Marvin


jpp

unread,
Oct 2, 2009, 10:27:18 AM10/2/09
to Project Lombok
I also don't like |String a, String b| because you don't see
immediately which one is the opening | and which one the closing |,
especially with longer type names and multiple line of similar code. #
() feels better because we still get params inside parentheses, which
people are used to.

> With closures this changes; there are now at least 2
> methods you could be targeting.

Your "at least 2" got me thinking. If it is more than 2, then "inner"
and "outer" don't make much sense any more. Which "outer" are you
targeting? Then, prefixing return with the method name (agreeably,
type name would make less sense than method name) might then be the
best chance of making this possible at all.

> We have discussed both labelled returns and type-specified returns
> before. It might work as an alternative, but I (and probably Roel, if
> our last chat on this topic is any indication) feel pretty strongly
> that a vanilla "return" should always be a syntax error inside a
> closure.
>
> The big problem, then, with using type names, is that part of the
> closure spec we're working on doesn't force you to even know what the
> type name is; it's something you can ask your IDE if you want, but you
> don't need to explicitly know it. So, you'd have to write:
>
> Collections.sort(myList, #(String a, String b) {
>     Comparator.return a.length() - b.length();
>
> }
>
> note how Comparator snuck in there.

Right. It wouldn't be good to force the programmer to know the method
name or type name here. For this *and* for the sake of code
compatibility, of the possibility to copy-paste code from & to
closures, I would still argue than an unqualified "return" should
default to exiting the innermost method, i.e. the current closure
code. Wouldn't you agree that this is what you're most likely to do
anyway, and that returning from the enclosing method from inside the
closure would be an "advanced feature" anyway?

J.-P.

Reinier Zwitserloot

unread,
Oct 2, 2009, 12:08:22 PM10/2/09
to Project Lombok
Well, Marvin, you said it: People want inline closures too.

There's a second, more important issue. The way Roel and I figured out
a much simpler proposal for transparent closures _requires_ you to
either run or discard the closure before your scope changes. This
means that, for transparent closures, you _MUST_ _neccessarily_ pass
them to a method. In other words, the only closures in our proposal
are inline closures. You can of course still use inline methods as a
closure: Just toss a block around it. Also, if you don't need
transparency, then everything goes.

Your syntax doesn't seem particularly compelling:

1. Why do you need bars for inline methods? Inline methods should of
course look like normal methods: returnType name(paramType paramName)
{ statements; }

2. Yo ucan't assign an (inline) method to a java.lang.reflect.Method
type. That makes no sense; how would you invoke it? What would you
pass for instance? 'this'? You could make a different class named
Method, but that would be rather confusing, and is even worse than
structural typing: You'd have _NO_ typing whatsoever, and the only way
to call it would be to give a variable number of parameters, with zero
typing info. That's so far removed from java that it's not worth
considering.


The problem with making just "return" be the local return is that it
screws up transparency. This seems like a trivial thing to give up for
something like comparator, but lets try this again, but this time with
a hand-rolled synchronized block, based on java.util.concurrent locks:

public String getFoo(String key) {
lock.doGuarded(|| {
String x = cache.get(key);
if (x == null) {
x = calculateFoo(key);
cache.put(key, x);
}
return x;
});
}


Seems fairly natural, except of course it wouldn't work - that return
would be erroneously interpreted as trying to return from the closure,
which would give you a compile time error: the closure parameter to a
doGuarded() block should be returning void. In this case you'll figure
it out fairly quickly, but with if you meant a long return but the
compiler accepts your faulty code silently because the closure has the
same returntype as your method? Then nasty bugs occur that are much
harder to find. Hence our continued insistence that plain return will
not be allowed inside closures to avoid this confusion.

There's a second problem there, of course: Definitive Assignment
rules. Even if you fix the return to a long return, you'd still get a
compiler error: You must return something from this method. doGuarded
will actually ALWAYS run the closure, OR break out with an exception,
but the compiler doesn't know that. Allowing the doGuarded method to
declare this fact is something we're toying with. That's a different
can of worms that we'll open at a later date.

jpp: Yes, bars don't have open and close variants, and this bothers us
too. All the paired symbols are taken though, so you'd have to create
hybrids, something like: [| to open and |] to close (bracket-bar and
bar-bracket). Making something that is grammar-compatible with vanilla
java that involves braces, brackets, angles, or parens is hard unless
you double up on symbols.

On Oct 2, 4:20 pm, Marvin Greenberg <marvin.greenb...@gmail.com>
wrote:

Jacek Furmankiewicz

unread,
Oct 3, 2009, 9:07:22 PM10/3/09
to Project Lombok
For the return value issue, couldn't you just assume the last line of
code in the closure is the return value (like in Erlang and Scala
functions)?

v6ak

unread,
Oct 4, 2009, 4:44:32 AM10/4/09
to Project Lombok
OK, I think that || should cause at least warning.

I suddenly understand how much is "short return" confusing.
Note that it is my mistake (or a feature) that I was too much focused
to the syntax so I didn't wonder "Why not boolean return?".
I don't fully understand how would "outer return" work. There are more
issues. Think about this:
public static Comparator<String> getSpecialComparator(final Something
argument){
return #(String a, String b){
...
outer return sth;
}
}

Are you going to generate throws declaration automatically? (There are
several reasons that I can write if you want.)

You wrote that it is neccessary to pass every closure to a method. I
understand some reasons. However, what about assigning in this way?:
Comparator<String> myComparator = #(String a, String b) ...;

Note that NetBeans allows to use C-like # (see
http://bm2.googlecode.com/svn/trunk/src/midlet/BombusMod.java ), so it
would be useful to warn when line (except whitespace on the left side)
starts with "#" that is interpreted as closure.

I agree that the syntax is strongly affected by progress. The best way
to solve it is inventing a totaly new syntax without inspiring in
existing one. Well, I am dreaming.

It is true that there is no "left side |" and "right side |" but only
one "|". However, it is not IMHO an important issue, because:
* the parameter list is usualy not long
* you can simply guess it

Reinier Zwitserloot

unread,
Oct 4, 2009, 4:14:07 PM10/4/09
to Project Lombok
Letting the last expression count as the return value is problematic;
not all expressions are also legal as a statement (in fact, virtually
all expressions in java aren't statements, except for method calls,
pretty much, which can be both). There's also a small type checking
disaster in trying to tell the difference between returning void and
returning the type of the last expression. All of this adds up to why
BGGA has that weird "last expression must NOT end in a semi-colon"
rule that is causing so much griefing of BGGA's syntax.

And I tend to agree with that griefing. It looks crazy. It goes
against all your muscle memory. And yet, trying to remove that
restriction - to let you put that semi-colon in, is a nightmare to do
right on the grammar level. I get why its there.

Now, if somehow this was some sort of grand solution, it might be
worth the pain (either the pain of turning the grammar into
frankenstein, or the pain of going against a decade of muscle memory),
but it really isn't. One major flaw is that it becomes very difficult
to return from the inner method in the middle of the method body.
Another is that its not exactly self-explanatory. It looks great if
you program scala more than java, but clearly that's not what lombok
is trying to design for.

v6ak: You have me convinced that "short return" and "long return" are
not the great eureka solution I thought it was. Possibly we can
somehow make "outer return" and "inner return" work. More likely we'll
have to try something else. These would all be easy to retrofit into
the grammar:

return[inner] foo;

innerreturn foo;

inner_return foo;

returninner foo;

return_inner foo;

inner.return foo;

return.inner foo;

Reinier Zwitserloot

unread,
Oct 4, 2009, 4:43:18 PM10/4/09
to Project Lombok
Allright, because it seems to help the discussion, I'll make a rough
sketch of how our closure proposal works.


There are at least 3 concepts in java code that change meaning
depending on its lexical context:

break, continue, and throw.

Take 'throw' for example: If the type of the expression that you throw
is checked, then the compiler will keep walking up the lexical scope
tree (the braces in java code) until it finds a legal construct that
gives you the right to throw this type. Either a try block that
catches the checked exception type (or a supertype), or a method node
that declares that it throws this type (or a supertype). If you copy/
paste a throw statement around, all of a sudden it can become illegal
java code, merely because its lexical context changes.

Similar rules apply to break and continue; they are defined as
breaking/continuing the nearest enclosing breakable/continuable node.
A similar rule hold for labelled breaks and continues.


Now we come to the issue of having transparent closures: The meanings
of these statements are essentially supposed to maintain their meaning
(remember, their meaning is intricately bound to the exact place they
appear in the source file: Their lexical scope), but they aren't
necessarily RUN when this scope holds. Clearly then, trying to say
that a closure's meaning doesn't change (So called "Tennant's
Correspondence Principle", something team BGGA takes very seriously),
is a pipe dream: The moment you use throw, break, continue (and to a
lesser extent, return), Tennant's Correspondence Principle is
impossible to maintain unless the lexical context matches the runtime
context. Let's write some code that shows how crazy this gets:

-----

Comparator<String> c;

try {
c = new Comparator<String>(String a, String b) { throw new
IOException(); };
} catch (IOException e) {
System.out.println("Hello!");
}

Collections.sort(myList, c);

-----

What does the above code even mean? Should it compile? It seems
reasonable to compile it: An IOException is thrown but in a lexical
context where it is allowed (it appears inside of a try/catch block
that catches IOException). However, where it is RUN, there is no
IOException guard. So, how do we run this? Should the lexical context
somehow be remembered and tacked onto the closure, so that the
exception handler can be run? This is called a continuation, would be
virtually impossible to retrofit into java, is not at all obvious from
a casual read, and has serious complications especially when you try
to apply this to break/continue. Should the IOException just be
thrown, even though there's no guarding statement? That's tantamount
to getting rid of checked exceptions altogether, and still won't help
when using break/continue.

So, what to do?

Here's what BGGA does:

For break and continue, you're on your own. If the context is still
there, it'll work. If not, you get a "TransferError", and that's that.
Some people (including myself) find this unacceptable. For exceptions,
they DO handle it better; each closure can carry with it the
exceptions it may throw, as generics. That way, something like
Collections.sort() can be written as:

public static <T> void sort(List<T> list, Closure<T, T, Integer,
throws E> closure) throws E;

the important bit is the throws E stuff: The closure 'type' you pass
into this method decides what the method will throw. Thus, if you
define the closure as throwing IOException, then, when you use it to
sort a list, that sort call will also throw IOException. Checked
exception system saved. But at what cost? This "throws E" stuff has a
bunch of rules associated with it; it's actually a disjoint type - you
can of course throw different kinds of checked exceptions in 1 closure
block, so "E" could stand for: "IOException *OR* SQLException". Java
doesn't have a concept for this kind of thing, and thus these 'E'
types aren't usable as an actual type. You can only just 'throw' it
onwards. Yich.

So, BGGA has a crappy solution for exceptions and no solution at all
for break and continue. As a saving grace, it allows a syntax to
declare an 'unsafe' closure, which doesn't let you break, continue,
and return out of the method. This 'safe closure' system has its own
problems. One of them is that it won't help the code snippet above: It
wont stop you from defining a closure in method A and using it in the
same method, but in a different place, so that any breaks, continues,
and throw statements are still weird.



So, in our closure proposal, instead of trying to solve this clearly
unsolvable problem, we just roll with it: A closure ceases to be legal
the moment the lexical context changes even a little bit. Which simply
means: Either you get a closure as a parameter to your method and it's
legal all throughout your method (but you may NOT let it escape into a
field or another method that hasn't been specifically compiled as "I
take a closure here"), _OR_ you define it but don't save a reference
to it. Which is utterly useless except when you pass it inline as a
method parameter, so that's what you do: Create them only inline, and
nowhere else.

Note that _EVERY_ closure supporting language struggles with making
long break, long continue, and long return make sense inside closures.
Java is pretty much the only language with checked exceptions, so
that's just another added complexity. In that sense, our rule is
'novel' - no other language has it. But, I and Roel very strongly feel
its the obvious right answer: You don't give up that much flexibility,
and you eliminate an enormous amount of intrinsic complexity - instead
of trying to solve the unsolvable, we roll with the punches and
ENFORCE, at the compiler level, that a closure, if it is run at all,
is always run so that the stack, as it existed at the time you define
the closure, is still there (with maybe some more methods on there,
that's fine).

v6ak: I have no idea what you're talking about with Netbeans allowing
# in java source. No it doesn't - # is not legal in java source,
outside of comments and string literals, period. If you're talking
about those # marks inside magic comments:

(A) Magic comments are effing retarded, and
(B) a preprocessor is effing retarded.

Possibly I didn't understand what you meant.

jpp

unread,
Oct 5, 2009, 4:29:12 AM10/5/09
to Project Lombok
After reading your explanations, I think I'm also convinced that it's
a very good ideas to force closures to be run in their lexical,
compile-time stack. It looks like it solves quite a few issues. I like
your example with throw, which shows very well the kind of trouble we
could run into.

Nevertheless, it raises a few questions, like how would I write a
closure version of addActionListener(), for instance. Surely I won't
run the action listener right away; but equally surely, this is one of
the main spots where we all want closures to deal away with the
verbosity of anonymous inner classes. How would you solve that? Could
you also comment a bit as well on how the closures would be implemented
—would it be some kind of elaborate syntactic sugar for inner classes
with bound variables in the current lexical scope?

Regarding the various forms of "inner return": I dislike the
underscore and I'm glad I (almost) never see it in Java. I'd favor
something like inner.return, of the vein of OuterClass.this or
expression.super(…). But I'd still wonder what "inner" and "outer"
would mean if there are several nested closures within one another.
"inner" would always mean "innermost", and "outer" always the top-
level enclosing method?

I woud still be bothered by the need to add this "inner" to my return
statements while I'm transitioning my verbose inner-class code to the
new closures. I know that for all currently existing code in those
anonymous inner classes, "return" means "inner.return", as
"outer.return" if currently never possible. In other use cases, like
your lock.doGuarded example, it seems clear that "return" means
"outer.return". Actually, what "return" means seems very much to be
tied to the kind of method you're calling. Could we thus tag method
parameters (maybe with @InlineReturnSemantics, or something shorter)
where want "return" to mean "outer.return"? The currently untagged
method/parameters would still behave as to interpret "return" as a
traditional return.

This would:
1. Give "return" its natural meaning in each context. For an
ActionListener, it would return from the handler. In a doGuarded
method, if would return from the caller.
2. Allow the compiler to know whether in a given method, a passed
closure or ActionListener-like object should be forced to run at once
(if tagged with @InlineReturnSemantics) or can be saved, e.g. in a
listener list, and safely invoked later.

Closures passed as arguments to untagged parameters would not be
allowed to call outer.return; those passed as arguments to tagged
parameters could call inner.return if they need to.

(I had also thought about tagging the implemented interfaces
themselves, but this is too restrictive, as one could e.g. want to
store a Runnable as a callback to invoke later, or want to run it
right now as in the doGuarded example.)

Reinier Zwitserloot

unread,
Oct 5, 2009, 5:12:40 AM10/5/09
to Project Lombok
I totally forgot to mention this bit:

Transparency is fun, but you don't always need it. In many cases, it's
actively a bad thing, such as when you're making a closure that's
going to "travel the world" so to speak: It's going to run at a wildly
different time, by a completely different lexical context, probably in
a different thread.

That's where CICE comes in:

widget.addActionListener(new ActionListener(ActionEvent event) {
/* do something */
});


This is just simple syntax sugar for creating anonymous inner classes.
Break, continue, return, and 'throw' all change meaning when you
create one, just like they do now when you create an anonymous inner
class literal. The only difference we'll make with cice is that an
unqualified "this" will by default refer to the outer scope and not
the inner scope, as you rarely need the inner scope this. You can
still get it: "ActionListener.this" would refer to the inner this.


The transparent closures would be implemented via the same thing,
really: anonymous inner classes. Exceptions will be made transparent
just by throwing them (the VM doesn't care about checked exceptions -
it's the javac compiler that refuses to compile your code, so the way
around it is to just compile it). For break, continue, and return,
we'll have to use exceptions to clean up the stack just like BGGA
does. We don't have the luxury of adding a new top-level Throwable so
our transfer throwables will have to subclass Throwable. We get around
the potential migration issues here (code that 'catches throwable'
would also get in the way of outer return/break/continue) by
_requiring_ methods that want to take in closures to be specially
marked. As part of the contract of marking your method with "I take
closures here", you must ensure you don't eat the transfer throwables.

Thus, you could redefine Collections.sort as such:

public static <T> void sort(List<T> list, do Comparator<T> comparator)
{ /* code as if comparator is just a Comparator */ }


The "do" keyword used in front of the type of the second parameter is
the flag that says: I take closures here. As part of the deal, when
this code is compiled, the compiler (well, lombok's extension to it,
obviously), will check that 'comparator' is *NOT* allowed to escape.
You may not return it, you may not store it in a field, and you may
not pass it to another method, unless the method you're passing it to
is also marked as accepting closures. This way we ensure that the
closure cannot be used elsewhere. In the actual implementation of
Collections.sort, none of these rules would prevent it from being
compiled.

We *MAY* consider allowing some sort of 'disable these rules' hack.
That way you can actually move closures around. As long as you very
carefully transport all exceptions (including the transfer throwables)
back to the originating thread, there should be no problem. This would
allow you to write a Swing.invokeAndWait, or a parallel array
operation, via closures, eventhough you can't write those things
without running into this escape detection mechanism. It's a niche
feature though - other than Swing.invokeAndWait and parallel arrays,
there aren't many use cases.


For some closure usages, defining the closure as a new break/continue
context makes sense: For example, if you had written java5's foreach
syntax as a closure, clearly you would want "break" to break out of
this new for-each-like thing, and 'continue' to continue it. To allow
this, we were thinking of letting you write "for" instead of "do".
This does mean you can't tell in the code that declares a closure if
break/continue got a new context or not, so we're not 100% sold on
this particular one just yet. FCM's control abstraction addition
instead has a new for syntax that calls closures; we may instead go
with that.


For non-transparent closures (so, CICE closures), "return" is just
that: the usual inner return. The inner.return and outer.return syntax
would only be for the new transparent closures.

Maybe we'll even allow labelName.return, so that you can return 2
levels up in a stack of 5 nested closures, but that's kind of a niche
deal. I'd be allright if I can only return either from the innermost,
or the outermost, level, without the option of returning from a
closure in the middle of a bunch of nested ones.


It's fairly obvious that any given closure declaration needs a bunch
of meta-parameters, such as:

- is this a new break/continue scope?
- What are the semantics of the 'return' statement?
- Will this closure only be run with context intact (transparency
please!), or will it be escaping its stack context (no transparency!)

The question is: Where will this parameter be set: On the site that
receives the closure, On the SAM type that is backing the closure, or
where you write the closure?

Right now we have a sort of mixed bag here: break/continue scope is
set on the closure receiver site (via using the 'do' or 'for'
keyword), the semantics of the return statement are made invariant via
the 'inner' and 'outer' syntax, and whether or not the closure is
transparent is set at the site where you write the closure (Using a #,
or pipes, means: transparency. No hash means: no transparency).

Tagging the SAM types backing the closures is a bad idea, for the
reason you stated. Another nice example is Comparator: When you pass a
Comparator to a TreeSet, it's unsafe, but when you pass it to
Collections.sort, it's safe.

Perhaps we should endeavour for consistence here and either move all
these parameters to the declaration site, or to move them all to the
recipient. If it won't become too much of a chore to type, I prefer
having all this stuff on the declaration site, as that would improve
readability a bit - otherwise you'd have absolutely no clue if a
"return" inside a closure means an inner or outer return without
opening up the definition of the method that the closure is being
passed to.

So, everything-at-declaration means:

- The 'do'/'for' keyword syntax goes away, and instead if you want a
new break/continue context you'd have to write something like: "for #
(String a, String b)", or "for | | statements;". One could consider
moving the for away from parameters, so you'd get:

for Collections.sort(myList, | | {statements;});

But now you can no longer set different for/do parameters if your
method takes more than 1 closure. Python's for/else could not then be
written as closure, because the for block needs for semantics, but the
else block doesn't. Not the end of the world, but would be nice, and
more consistent with the other syntax suggestions, if this for/do
distinction is set on the closure itself, and not on the method call
that involves this closure.

- "inner.return" and "outer.return" stay.

- There's a forced syntactic difference between a CICE-like non-
transparent closure, and a transparent closure, most likely by making
either a # or a pipe symbol, depending on how we write up the syntax
for the closure's param lists, mandatory, as a flag to know which of
the two types you want.


On the other hand, moving everything to the receiver side, you could
theoretically make the syntax a lot simpler:

- The CICE-like syntax would be legal anywhere, and you automatically
get transparency if the method you're calling says that's okay.

- 'break' and 'continue' automatically change meaning depending on
what you're passing your closure too.

- 'return' will just do the right thing.


The more I think about it, the less I'm liking this 'receiver side
chooses' stuff: It would mean that a later change in the API can
totally change the meaning of your code, and the kinds of changes that
would occur won't always trigger obvious compile time errors. From a
readability standpoint, it really sucks too. If you see a closure and
aren't familiar with the method that's being called with this closure,
you'd be completely in the dark as to what's going to happen there.
With declaration-site-parameters, you may not know what the closure
will do to this block, but you do know the block will be called 0, 1,
or more times, cannot escape from its stack, and you know exactly how
the code inside the closure interacts with the code outside of it -
you know what break and continue would be doing, as well as what that
return statement means.

It's worth noting that BGGA messed this up; for/do semantics are
decided by the recipient, all closures are transparent but
nevertheless you can be prevented from attempting outer return/break/
continues by changing the declaration site's arrow symbol from => to
==>, and the semantics of the return statement are decided by the
syntax of the return statement itself. No consistency.

jpp

unread,
Oct 5, 2009, 7:47:01 AM10/5/09
to Project Lombok
Don't you need receiver-side declaration of do/for anyway, in order to
check that those closures don't escape into the wild in the compiler?
do/for as modifier for parameters is fine, but "for Collections.sort
(myList, | | {statements;});" or "Collections.sort(myList, for | |
{statements;});" is weird. Especially because if we do implement some
kind of for mechanism, is it not unlikely that "for" will be part of
the method name, and we wouldn't want it twice on the same line:

list.forEachFiltered( filter, for |Element e| {

});

Assuming you need it anyway at the receiver, the caller could still
tell whether transparency is wanted or not with an annotation before
the closure:

list.forEachFiltered( filter, @Transparent |Element e| {

});

I'd say the hash syntax is more practical especially when no
parameters are there; it could simply prefix the block:

lock.doGuarded( #{
// work
});

which looks better than this:

lock.doGuarded( | | {
// work
});

The hash would then be the universal prefix for transparent closures,
and any needed params would find their place in parentheses as usual.

lock.doGuarded( #(Object data) {
// work
});

OK, I am now understanding that you're introducing two new constructs:
transparent and nontransparent/traditional. But it is a bit arbitrary:
why two different new constructs, apart from being able to tell which
ones should be transparent and which ones traditional? Maybe we could
have a single hash for nontransparent ones, and a double-hash for
transparent ones? This would also eliminate the need for a too verbose
@Transparent annotation: if all meta-parameters must be declared by
the caller, then they should be short.

// transparent mode
Collections.sort( list, ##(String a, String b) {
// or maybe this? @#(String a, String b)
// or this? @(String a, String b)
inner.return a.compareTo(b);
});

or this, which would also work:

// nontransparent mode
Collections.sort( list, #(String a, String b) {
return a.compareTo(b); // unqualified return
});

and

// nontransparent
Map<String,String> = new TreeMap<String,String>( #(String a, String b)
{
return a.compareTo(b);
});

// nontransparent
button.addActionListener( #(ActionEvent e) {
field.setText("clicked");
});

The problem with the line "widget.addActionListener(new ActionListener
(ActionEvent event) …" is that there is the word "action" on this line
alone three times, and this is quite a common pattern for the
XYZListeners. If we can get rid of one of those, then so much the
better; including for the CICE-style closures.

Reinier Zwitserloot

unread,
Oct 5, 2009, 12:04:48 PM10/5/09
to Project Lombok
We definitely need the receiver to state that they are taking on a
closure. We don't need them to state if break/continue have special
meaning - that will all be sorted out when lombok converts the closure
declaration to an anonymous inner class.

It would be kind of a weird precedent if we enforced the rule that all
for-based closures must be passed to methods that start with "for" in
their method name, though, it feels like an oddly simple solution
compared to all the other ones. There's still the very significant
problem that the 'for/do' modifier really should travel with the
parameter and NOT with the entire method. Again, I'll dig up the
python for/else block example: You'd pass 2 closures to this method,
and only 1 of them should have special semantics.

The 2 construct rule is certainly not arbitrary: We have a boatload of
strictly _not_ transparent "closures" out there: Anonymous Inner
Classes. They are fundamentally not transparent, so trying to somehow
adapt them is just going to cause a lot of pain. Nevertheless, there
are loads out there, and there are loads of use cases where a light
sugar coating of that syntax is really all that you need. I really
dislike BGGA's rule of "=>" and "==>" creating different closures, and
I get the same sense of fear when talking about using # or ##. It's
just arbitrary cartoon swearing. Doesn't feel right.

Will take the ridiculous notion that you repeat "Action" three times
in a common pattern under advisement; we should try to avoid this if
at all possible.

jpp

unread,
Oct 5, 2009, 12:40:21 PM10/5/09
to Project Lombok
The *method* name carrying certain semantics? Hmm… A weird precedent
indeed… Would the rule forbid to name other methods like this,
starting with "for"?

> The 2 construct rule is certainly not arbitrary

What I meant by arbitrary is not that the distinction between
transparent and "traditional" is arbitrary (I of course agree it
isn't), but that the difference in the syntax (new ActionListener
(ActionEvent e) {…} vs #(ActionEvent e) {…}) is: why force the more
verbose syntax on the nontransparent closure.

> Will take the ridiculous notion that you repeat "Action" three times
> in a common pattern under advisement; we should try to avoid this if
> at all possible.

Cool.

(Yet another) syntax proposal: maybe transparent closures could have
different block delimiters, instead of the double hash. This shows
that something new is happening in there.

// transparent
lock.doGuarded( #(Object data) {|
// work
|} );

vs.

// traditional
button.addActionListener( #(ActionEvent e) {
// handler
});

Looking forward to seeing what you guys settle on eventually.

Cheers,
J.-P.

Peter Becker

unread,
Oct 5, 2009, 4:38:59 PM10/5/09
to project...@googlegroups.com
jpp wrote:
> The *method* name carrying certain semantics? Hmm… A weird precedent
> indeed…
Reading these opening lines before my first coffee in the morning they
seemed a very cynical view of the state of programming at first :-)

Peter

PeLe

unread,
Oct 5, 2009, 4:42:09 PM10/5/09
to Project Lombok
The idea of only allowing closures to be specified inline, as method
parameters, so that we can achieve break/continue/return/exception
transparency with minimum complications is interesting but I see two
problems even with this approach, that have not been mentioned in the
posts yet.

First is concerning the currently proposed syntax that expects to
infer the "SAM type to be extended/implemented" from the method
parameter type. I don't see how this should work in the presence of
"overloaded methods". Neither have I found any info on that issue in
BGGA specification. Do you know how Neal dealt with this?

Second is exception transparency issues. Take the following for
example:

void doSomethingWith(Runnable r) {
try {
doMeetSomePreconditionsWhichMightThrowIOException();
r.run(); // since run method does not declare IOException, noone
is expecting one and....
}
catch (IOException e) {
// ... might catch it here although he/she is only trying to
handle
// exception originating from doMeetSomePreconditions....
}
}

void test() throws IOException {
doSomethingWith(#() {
throw IOException();
});
}

jpp

unread,
Oct 5, 2009, 6:02:11 PM10/5/09
to Project Lombok
I apologize if it sounded cynical! I was just thinking aloud about
it :-)

jpp

unread,
Oct 5, 2009, 6:13:10 PM10/5/09
to Project Lombok
> First is concerning the currently proposed syntax that expects to
> infer the "SAM type to be extended/implemented" from the method
> parameter type. I don't see how this should work in the presence of
> "overloaded methods". Neither have I found any info on that issue in
> BGGA specification. Do you know how Neal dealt with this?

Good point. In this case, it may be desirable to be able to explicitly
specify a type, both for transparent and nontransparent closures. So
maybe we could have a CICE-like syntax with the different block
delimiters when a type specification is needed. The compiler could
output an error in ambiguous cases.

// transparent, unambiguous
lock.doGuarded( #(Object data) {|
// work
|} );

// transparent, ambiguous, with type spec
lock.doGuarded( new RunnableWithObject(Object data) {|
// work
|} );

> Second is exception transparency issues. Take the following for
> example:
>
> void doSomethingWith(Runnable r) {
>    try {
>       doMeetSomePreconditionsWhichMightThrowIOException();
>       r.run(); // since run method does not declare IOException, noone
> is expecting one and....
>    }
>    catch (IOException e) {
>       // ... might catch it here although he/she is only trying to
> handle
>       // exception originating from doMeetSomePreconditions....
>    }
>
> }
>
> void test() throws IOException {
>    doSomethingWith(#() {
>       throw IOException();
>    });
> }

I guess it could be solved by not actually throwing the declared
checked exception thrown in the transparent closure, like IOException,
but some wrapper instead, like LombokLongThrowable, which would be
unwrapped before being passed further to test() as IOException, and
(here in this case) thrown back to test()'s caller as usual. Actually,
the same mechanism that would be used to implement long break and long
continue (if I've understood Reinier correctly).

Jeff Schnitzer

unread,
Oct 5, 2009, 6:34:53 PM10/5/09
to Project Lombok
I haven't been following this thread very closely, so I apologize if
this sounds naive, but...

Why don't you just adopt the Groovy syntax as-is?

There are significant numbers of Groovy programmers already familiar
with the syntax (and thus ripe to adopt Lombok), they've already
worked out many of the kinks (the language has had one major revision
already), you might be able to leverage some of the IDE plugin code,
and you can ride the coattails of existing Groovy books and
documentation.

As someone who codes primarily in Java but uses Groovy for occasional
scripting tasks, this would seem ideal.

At the very least, how about looping James Strachan into this
conversation? I'm sure he would have some great advice.

Jeff

Reinier Zwitserloot

unread,
Oct 5, 2009, 7:20:27 PM10/5/09
to Project Lombok
Hmm. We sort of went with "Let's keep CICE pretty much untouched, and
then come up with something completely new for transparent closures".
Perhaps that was a bad presumption. Different block delimiter might be
an option. Because java has never seen anything anywhere near
transparent closures, something out of left field - e.g. something
that's going to make people kneejerk: Ewwwww, that's not java-like! -
that might be warranted. Then again, it makes people go ewwww.

Reinier Zwitserloot

unread,
Oct 5, 2009, 7:23:36 PM10/5/09
to Project Lombok
PeLe:


Overloading sucks. If you're dumb enough to try it, you deal with the
consequences. The inference engine in java is notoriously weak, and
method overloading won't change this. Basically, if you've overloaded
a closure-accepting method, expect things not to infer very nicely. We
will always offer a way to explicitly force the type name, so you can
still use overloaded methods if you really really want to.

There's no issue with the exception catching: If you're going to take
a transparent closure, you _HAVE TO_ declare this in your method
parameter syntax. You've just mentioned one of the reasons for this:
There are certain preconditions that you need to meet when you write a
closure-accepting method, and one of the preconditions is that you
understand that a closure can throw _anything_.

NB: You should always assume any method can throw anything. But, emany
people don't actually make this assumption, so it's a valid issue you
raised - fortunately dealt with by forcing a closure-accepting method
to be explicit about that fact.

Reinier Zwitserloot

unread,
Oct 5, 2009, 7:25:45 PM10/5/09
to Project Lombok
Please, by all means, contact James Strachan and point him towards
this thread. Do you have some groovy syntax examples for me, and/or a
pointer to the proper page in the groovy documentation?

I doubt we can 'just take over' their syntax - our closure proposal is
fairly novel in how it works. For example, because our closures must
neccessarily be passed to a method, the syntax needs to be designed
around the fact that it'll be particularly paren-soup prone. Still,
lombok is all about stealing the great bits from other languages, so
examples would be excellent.

PeLe

unread,
Oct 6, 2009, 9:02:40 AM10/6/09
to Project Lombok
On Oct 6, 1:23 am, Reinier Zwitserloot <reini...@gmail.com> wrote:
> PeLe:
>
> Overloading sucks. If you're dumb enough to try it, you deal with the
> consequences. The inference engine in java is notoriously weak, and
> method overloading won't change this. Basically, if you've overloaded
> a closure-accepting method, expect things not to infer very nicely. We
> will always offer a way to explicitly force the type name, so you can
> still use overloaded methods if you really really want to.

The other possibility might be (in addition to allowing passing
closures inlined to methods only) to allow also assigning them to
final local variables. Their scope does not extend out of the lexical
block where they are defined in and their assignment to other
variables can be tracked in a similar way as you are going to track
method parameter variables.

>
> There's no issue with the exception catching: If you're going to take
> a transparent closure, you _HAVE TO_ declare this in your method
> parameter syntax. You've just mentioned one of the reasons for this:
> There are certain preconditions that you need to meet when you write a
> closure-accepting method, and one of the preconditions is that you
> understand that a closure can throw _anything_.

Oh, I see. You are going to mark them the other way around. So non-
marked parameters will only accept restricted closures and marked
parameters will accept both transparent and restricted. The above idea
about final local variables might then be extended to:

void doSomethingWithTransparent(@Transparent Runnable r) throws
MyException
{
@Transparent Runnable tr = r; // legal
Runnable rr = r; // ILLEGAL

try
{
r.run(); // you can make compiler pretend as though run method
declared "throws Exception"
// - not only "be prepared" but "be forced" to
handle any exception thrown from transparent closure
}
catch (Exception e)
{
throw new MyException(e);
}
}

void doSomethingWithRestricted(Runnable r)
{
@Transparent Runnable tr = r; // legal
Runnable rr = r; // legal

r.run(); // compiler knows r is restricted so it behaves normally
(not pretending run() throws Exception)
}


void test()
{
Runnable outer = null;

try
{
final Runnable r = #() {
System.out.println(); // legal
if (...) return; // ILLEGAL
throw new IOException(); // ILLEGAL
};

r.run(); // legal
doSomethingWithTransparent(r); // legal
doSomethingWithRestricted(r); // legal
outer = r; // legal

@Transparent final Runnable rr = #() {
System.out.println(); // legal
if (...) return; // legal
throw new IOException(); // legal
}

r.run(); // legal
doSomethingWithTransparent(r); // legal
doSomethingWithRestricted(r); // ILLEGAL
outer = r; // ILLEGAL
}
catch (IOException e)
{
// deal with it
}
catch (MyException e)
{
// deal with it
}
}


>
> NB: You should always assume any method can throw anything. But, emany
> people don't actually make this assumption., so it's a valid issue you
> raised - fortunately dealt with by forcing a closure-accepting method
> to be explicit about that fact.
>

I think many good programmers assume any method can throw any
unchecked exception and only those checked exceptions declared on a
method. At least this is the way the world was until "sneaky throwers"
and "checked exception eliminators" penetrated the scene.

Still, majority of code is written with those assumptions in mind and
anything not obeying this "convention" segments the code into two
incompatible styles that don't mix together very well.

Regards,
Peter

PeLe

unread,
Oct 6, 2009, 9:30:47 AM10/6/09
to Project Lombok
I'm resending the code snippet from above because of some syntactic
mistakes:

void doSomethingWithTransparent(@Transparent Runnable r)
throws MyException
{
@Transparent Runnable tr = r; // legal
Runnable rr = r; // ILLEGAL
try
{
r.run(); // you can make compiler pretend as though
// run method declared "throws Exception"
// - not only "be prepared" but "be forced" to
// handle any exception thrown from transparent
closure
}
catch (Exception e)
{
throw new MyException(e);
}
}

void doSomethingWithRestricted(Runnable r)
{
@Transparent Runnable tr = r; // legal
Runnable rr = r; // legal

r.run(); // compiler knows r is restricted so it behaves
// normally (not pretending run() throws Exception)
}

void test()
{
Runnable outer = null;
try
{
final Runnable r = #() {
System.out.println(); // legal
if (...) return; // ILLEGAL
throw new IOException(); // ILLEGAL
};

r.run(); // legal
doSomethingWithTransparent(r); // legal
doSomethingWithRestricted(r); // legal
outer = r; // legal

@Transparent final Runnable tr = #() {
System.out.println(); // legal
if (...) return; // legal
throw new IOException(); // legal
}

tr.run(); // legal
doSomethingWithTransparent(tr); // legal
doSomethingWithRestricted(tr); // ILLEGAL
outer = tr; // ILLEGAL

v6ak

unread,
Oct 6, 2009, 9:51:14 AM10/6/09
to Project Lombok
> v6ak: You have me convinced that "short return" and "long return" are
> not the great eureka solution I thought it was. Possibly we can
> somehow make "outer return" and "inner return" work. More likely we'll
> have to try something else. These would all be easy to retrofit into
> the grammar:
I think that inner.return, innerreturn a and returninner are IMHO the
most java-like.

> I have no idea what you're talking about with Netbeans allowing # in java source
Well, I looked for it. It is probably for J2ME only, see e.g.
http://www.netbeans.org/kb/55/preprocessor-syntax.html . I don't think
that it is very important. I just noted about it.
I agree that the directives are obsolete.

Reinier Zwitserloot

unread,
Oct 6, 2009, 12:39:05 PM10/6/09
to Project Lombok
Peter, I don't quite think you understood how checked exception
transparency is going to work.


Runnable.run does not declare any checked exceptions. Therefore, even
if you explicitly say you will be taking in a transparent closure, the
compiler won't act like it throws any. Period. Your code snippets seem
to suggest that, if you write a method that takes in transparent
runnables, that you NEED to wrap the whole thing in a try/catch
Throwable just for the compiler to compile it. This is *NOT* true.


Let's assume for a moment the whole idea of closures doesn't exist,
and let's write a 'log entry and exit' wrapper:

public static void logEntryExit(do Runnable run) {
logger.log("Start");
try {
run.run();
} finally {
logger.log("End");
}
}

now, let's call it, but with code that throws an exception:

void test() {
try {
logEntryExit(#() {
throw new IOException();
}
} catch (IOException e) { /* handle it */ }
}


everything seems to be in order; an IOException is thrown, but this is
okay, because its thrown inside a try block that has a corresponding
catch clause that will handle IOExceptions.


Now lets get closures back in here. What will actually happen?

What will actually happen, is that the logEntryExit method will be at
the top of the stack when the IOException is thrown, and logEntryExit
is not at all expecting this checked exception - after all,
Runnable.run() specifically declares that it does NOT throw
IOException. While javac would be bothered by this turn of events, the
JVM, which really doesn't know about checked exceptions (it'll happily
throw anything regardless of what javac thinks is legal or not - which
is why @SneakyThrows works without causing verification errors), isn't
bothered. So, let's presume for a moment that this code is actually
run. run.run() will throw an IOException, which will, after triggering
that finally block, propagate up the stack like all exceptions do.

And this is where it gets neat: Because we declared that transparent
closures *MUST* *ALWAYS* be passed directly as an argument to a
method, the unwinding of the stack will eventually hit the frame that
declared the closure; it will eventually hit our test method.

In this closure proposal, the closure would never have been compiled
unless throwing an IOException was legal at the point where you wrote
the closure (where you wrote that #). In our example, it IS legal. And
now the neatness kicks in: The IOException stops here, because it'll
be caught by the test() method's IOException handler. The hegemony of
checked exceptions is now restored.


The only time in which our checked exceptions hegemony was off was in
the logEntryExit method. Let's add to this scenario a little and say
that logEntryExit itself passes the closure onwards to another method.
We already said that you cannot let a closure escape, so that wouldn't
be legal, _unless_ the method you give it to is ALSO defined to take
closures (and thus gets the same restrictions). In this scenario,
clearly, the following holds:

Either (A) - the checked exception hegemony is intact: Any given
checked exception type can't happen unless your lexical scope allows
it (you're inside a method that throws X, or you're in a try block
that has a catch block with catch X), or

(B) you're calling the one method on a closure variable, on a
parameter you _EXPLICITLY_ put a 'I understand this is a closure'
marker on.


Thus, we create the following semantic rule:

*IF* you are invoking the one method on a closure type, then you MUST
NOT assume that it couldn't possibly be the source of a checked
exception. This is quite different from asking you to presume it WILL
throw these types. You don't have to handle them at all - the only
thing you must do, is let them propagate up the stack unharmed.

We can completely screw up our nice scenario by doing something like
this:

public void logEntryExit(do Runnable run) {
try {
Logger.initialize(); //can throw IOException
Logger.log("Start");
run.run();
} catch (IOException e) {
System.err.println("Failed to initialize logging system.
Logging disabled!");
} finally {
Logger.log("End");
}
}


This is all wrong - the presumption on the above code snippet is
clearly that the IOException *MUST* be coming from the
Logger.initialize() call, as Runnable.run doesn't declare IOException.
This would actually blow stuff up our closure proposal if you wrote
it, but we think this is acceptable, for two reasons:

1 - Presuming that a checked exception could not have come from a
method call that didn't declare it is ALWAYS A BUG (and NOT just
because of @SneakyThrows and disableCheckedExceptions - see the
footnote of this post), and more importantly,

2 - When you put a 'do' keyword on your method parameter, you
explicitly take on the responsibility to NOT do this. It's part of the
documentation of what it means to take on closures. It's almost
entirely transparent, but this is specifically something you'll need
to consider. As you explicitly need to add that 'do' keyword, no old
code will silently break during an upgrade. Someone explicitly has to
introduce a bug by adding a 'do' keyword without reviewing if the
method breaks this rule of not intercepting checked exceptions thrown
by its closure calls.

Programmers don't usually read all documentation, so this isn't a
foolproof mechanism, but it's good enough for us, especially
considering that there's absolutely no sane alternative. You could try
and wrap the exception in a carrier, but that won't save you if the
closure-accepting method catches Throwable. BGGA suggests creating a
new sibling of Throwable to avoid existing try/catch Throwable
statements from getting in the way of closure business, but lombok
does not have the luxury, as it cannot make any changes to the class
file format or the JVM rules - and that is a JVM change.



Footnote: Why you shouldn't blame @SneakyThrows and friends:

First of all, there are alternative JVM languages, which pretty much
all @SneakyThrow _EVERYTHING_. Scala does it. Jython does it. JRuby
does it. In fact, every JVM language except java sneaky throws. Java
is the only one that doesn't. Unless you adapt the rule that your code
is not guaranteed to be bug free if it interacts with class files
generated by something other than javac (which seems like a pretty bad
rule, and not at all in the vein of the write-once-run-everywhere
rhetoric of the JVM), you cannot make the assumption that a method
that doesn't declare it throws checked exception type X will in fact
never ever throw it.

But, let's say you make that rule. Then you STILL cannot guarantee it!

I'll prove it, with an example.

First, create Test1.java:

public class Test1 {
public static void main(String[] args) {
Test2.test();
}
}

then Test2.java:

public class Test2 {
public static void test() {
System.out.println("I can't legally throw a checked
exception!");
}
}

compile both (javac *.java).

Then, edit Test2 like so:

public class Test2 {
public static void test() throws Throwable {
throw new Throwable("Uhoh!");
}
}

now ONLY recompile Test2: "javac Test2.java".

Then, run Test1:

java Test1

and voila - a checked exception in a place where you never expected
it.

Q.E.D: Even without introducing alternative languages, @SneakyThrows,
disableCheckedExceptions, AOP, class rewriters, ASM, or any other
'voodoo', we have thrown a checked exception sneakily. It is therefore
always a bad idea to presume any given method couldn't possibly have
thrown checked exception type T because it does not have 'T' in its
throws list.

Reinier Zwitserloot

unread,
Oct 6, 2009, 12:39:07 PM10/6/09
to Project Lombok
Peter, I don't quite think you understood how checked exception
transparency is going to work.


Runnable.run does not declare any checked exceptions. Therefore, even
if you explicitly say you will be taking in a transparent closure, the
compiler won't act like it throws any. Period. Your code snippets seem
to suggest that, if you write a method that takes in transparent
runnables, that you NEED to wrap the whole thing in a try/catch
Throwable just for the compiler to compile it. This is *NOT* true.


Let's assume for a moment the whole idea of closures doesn't exist,
and let's write a 'log entry and exit' wrapper:

public static void logEntryExit(do Runnable run) {
logger.log("Start");
try {
run.run();
} finally {
logger.log("End");
}
}

now, let's call it, but with code that throws an exception:

void test() {
try {
logEntryExit(#() {
throw new IOException();
}

Reinier Zwitserloot

unread,
Oct 6, 2009, 12:44:22 PM10/6/09
to Project Lombok
Roel and I discussed some of the feedback from this thread and we've
decided that we're going to marry the transparent and non-transparent
syntax together. So, you can write your new actionlisteners like so:

button.addActionListener(#(ActionEvent e) {
/* do whatever */
});


This is probably going to mean that you MUST use "inner.return" (or
whatever we're going to come up with for inner return) even in these
kinds of closures, where outer.return isn't legal. Trying to do any
sort of long break/throw/continue/return behaviour is understood by
the grammar and parser, but will result in an explicit compile time
error that will mention that the closure is not transparent and thus
that you can't do what you're trying to do.

Furthermore, we'll probably expand the rules of inference so that you
can in fact use a method name as a deciding factor. Thus, you can
write:

#compareTo(String a, String b) { return 0; }

and the compiler will be able to figure out you meant to create a
Comparator closure even if you try to pass this off to a method that
has been overloaded with, say, both Comparator and some other SAM
type. So long as that SAM type's one SAM method name isn't also
"compareTo", of course.

Thus, all three would be legal:

#(String a, String b) {}

#compareTo(String a, String b) {}

#Comparator.compareTo(String a, String b) {}


with each level being better at figuring out that you meant to create
a Comparator.


On Oct 6, 3:51 pm, v6ak <v...@volny.cz> wrote:
> > v6ak: You have me convinced that "short return" and "long return" are
> > not the great eureka solution I thought it was. Possibly we can
> > somehow make "outer return" and "inner return" work. More likely we'll
> > have to try something else. These would all be easy to retrofit into
> > the grammar:
>
> I think that inner.return, innerreturn a and returninner are IMHO the
> most java-like.
>
> > I have no idea what you're talking about with Netbeans allowing # in java source
>
> Well, I looked for it. It is probably for J2ME only, see e.g.http://www.netbeans.org/kb/55/preprocessor-syntax.html. I don't think

v6ak

unread,
Oct 6, 2009, 12:51:01 PM10/6/09
to Project Lombok
> #compareTo(String a, String b) {}
Why not #Comparator(String a, String b) {} ? Is it a mistake or an
intention?

Reinier Zwitserloot

unread,
Oct 6, 2009, 3:11:29 PM10/6/09
to Project Lombok
A closure is closer to a method declaration than a class declaration.

Allowing both #compareTo and #Comparator is possible, though I wonder
if that's a bit too lenient. Collisions are unlikely; by convention
types are UpperCamel and method names are lowerCamel.

Another advantage of the method name is that you could use it to
create 'closures' around non-SAM types. Such as:

window.addWindowListener(#WindowAdapter.windowIconified(WindowEvent e)
{
});

In that case, WindowAdapter is mandatory (as inference won't be able
to make the jump from WindowListener, which is the actual type of that
parameter, to WindowAdapter, which is, as far as the compiler knows,
just one of many classes implementing WindowListener). Together with
traits, though, you really could have gone with:

window.addWindowListener(#windowIconified(WindowEvent e) {
});

which is nice.

Vít Šesták

unread,
Oct 6, 2009, 3:45:19 PM10/6/09
to project...@googlegroups.com
Ok, thanks for explanation.
I think that using class/interface name is more clear, especially when
you are reading the code.
However, I know that it is impossible to have everything. It is
impossible like having a very small mobile phone with very large
display. Just impossible.
BTW What is 'SAM'? I also don't understand how can I achieve the
simplified syntax with traits. However, I think that you can use the
simple variant when refering to class/interface too. It is also IMHO
more clear.

Reinier Zwitserloot

unread,
Oct 6, 2009, 4:44:58 PM10/6/09
to Project Lombok
Heh, hard to please everybody on this one. jpp wanted the method name
(see http://groups.google.com/group/project-lombok/msg/5af9c1fc729bc21c
). Doing both just because some people prefer one style over the
other is not a good idea, as it results in pointless style wars, so I
retract my suggestion to allow both. We'll toss a coin and allow one
or the other.

SAM stands for Single-Abstract-Method type. It's a concept from the
CICE closure proposal that refers to any type which contains exactly
1 method that has been marked as abstract.


Traits would help thusly: Traits allow you to give default
implementations for methods in interfaces. So, if you turn
WindowListener into a trait, where each method in the WindowListener
interface gets a default implementation of 'do nothing', then it would
make perfect sense to do something like this:

new WindowListener() {
public void windowIconified(WindowEvent e) {}
};

without getting a compiler error. Now you WOULD get an error: You need
implementations for all the other methods. That's why all these
XListeners also come in the XAdapter flavour. The above is exactly
what the closure inference engine would try to build when you write:

#windowIconified(WindowEvent e) {}

in a position where the inference engine sees that only a
WindowListener is going to work.


While the name is always going to be obvious ("Comparator" or
"compareTo" - either way, it's going to be obvious its a closure that
is going to compare things), "Comparator" is somewhat more useful in
finding the actual SAM type you're implementing. Which balances out
the notion that #compareTo opens the door to the nice interaction with
traits to eliminate the need for Adapter classes. So, it's a tossup.


On Oct 6, 9:45 pm, Vít Šesták <vit...@gmail.com> wrote:
> Ok, thanks for explanation.
> I think that using class/interface name is more clear, especially when
> you are reading the code.
> However, I know that it is impossible to have everything. It is
> impossible like having a very small mobile phone with very large
> display. Just impossible.
> BTW What is 'SAM'? I also don't understand how can I achieve the
> simplified syntax with traits. However, I think that you can use the
> simple variant when refering to class/interface too. It is also IMHO
> more clear.
>

jpp

unread,
Oct 6, 2009, 5:44:38 PM10/6/09
to Project Lombok
I really don't insist on having the method name if that complicates
things; I'd also be fine with the SAM type name instead.
ClassName.methodName makes a lot of sense though, especially for the
adapter classes, as you mentioned.

How about empty parameter lists? Will you force #() { ... }, or will #
{ ... } be legal?

I'm going to to mourn the loss of an easy "return" for CICE-style
closure, especially when trying to convince people to use lombok's
closures because it reduces verbosity of things like listeners, trying
to explain why it increases the verbosity of returning from the
method. I'd love to see "return" do the default thing in
nontransparent ones, and have a mandatorily qualified return
(inner.return, outer.return) for transparent ones. Oh well. :-)

You convinced me that writing something like your logEntryExit(do
Runnable run) example and assuming run.run() doesn't throw IOException
is a bug. But wouldn't you still consider that carrying the wrapped
exception in a wrapper until it reaches the closure's caller might
still be a good idea? Sometimes we can't control the code we're
calling, and the code could make this buggy assumption. Sure, "catch
(Throwable t)" will get them all. But javac would never force you to
catch Throwable, whereas it would force you (or at least all regular
programmers that aren't trying to trick javac :-)) to catch
IOException. Don't tell me that when you're writing IO code, you use a
separate try-catch block around each method that can throw IOException—
you'd just put one big try-catch around it all (if you can't use
@SneakyThrows, that is). Call the run.run() in the middle of it, and
you have a bug that's hard to detect, especially since exception
handling is, well, exceptional, and you might not detect the bug until
very late. You're going to carry long breaks and continues in wrapper
exceptions anyway to clean the stack, right? So why not add some
safety here and just also wrap the thrown checked exceptions that the
closure's method signature does not declare?

Can't wait to get my hands on the new Lombok with closures :-)

Cheers,
J.-P.

Reinier Zwitserloot

unread,
Oct 7, 2009, 9:44:24 PM10/7/09
to Project Lombok
Ever hear of C#'s coalesce operator?

It looks like this:

a ?? b ?? c;

most C# folk have no idea what it does. It resolves to the first
argument if the first argument is non-null, and resolves to the second
one otherwise. So, in a chain of them, it'll return the first non-null
value, or null if they're all non-null.

This is a stupid idea - operators are scarce resources you shouldn't
throw away frivolously, and they don't have javadoc. You can do it in
a library call like so:

public static <T> T coalesce(T... items) {
if (items == null) return null;
for (T item : items) if (item != null) return item;
return null;
}


except for one small but important difference: coalesce shortcuts.
Just like java's && and ||, any expressions to the right of a non-null
expression don't even get resolved. This saves processor cycles and
can be used to implement business logic.

Allowing # to be used without parens if you have no parameters, and
allowing the single expression shortcut, solves this problem for java.
You could then write:

coalesce(#varA, #varB, #varC.callExpensiveMethod());

If varA or varB is non-null, that expensive method will never be
called.

Unfortunately, this same feature shows why the #() syntax means
they'll have to be mandatory; it's too hard on the grammar side to see
the difference between this:

#(String a) {short.return a;}

and this:

#(a + b)


in the second case, those parens are intended as arithmetic (grouping)
parens. In the first, it's the delimiters for the parameter list.

It's an argument for using bars instead.

jpp

unread,
Oct 8, 2009, 4:58:40 AM10/8/09
to Project Lombok
> Unfortunately, this same feature shows why the #() syntax means
> they'll have to be mandatory

I trust you on this.

Just out of interest: what kind of input do you receive from the
parser? For instance, when you parse #(String a) { … }, do you get a
token stream like HASH, LPAREN, NONKEYWORD("String"), NONKEYWORD("a"),
RPAREN, that kind of stuff? So you'd have to determine yourself (I
mean, in Lombok code) that NONKEYWORD("String") is a type name and not
the beginning of an expression? How many symbols are you allowed to
"look ahead"? Looks like if you get 2, you can know whether the LPAREN
is opening a parameter list or not (two, because I think the only
other possibility to get a type name after an open paren is when
calling a static function, so you'd have the dot right after). Am I
mistaken here?

Just trying to understand how it works.

EDIT: Not exactly; you could get a type name like
"OuterClass.InnerClass" or simply "java.lang.String". Hmpf, headache
coming.

Reinier Zwitserloot

unread,
Oct 8, 2009, 7:41:55 AM10/8/09
to Project Lombok
Control us reversed; you declare how the grammar works in a custom
descriptive language, and then the paraer hands you nodes.

In this phase, the grammar has no idea whatsoever about the bindings;
it doesn't know if "String" refers to a variable, a type, or a label.
This is usually good, actually; the namespaces overlap so what do you
do when there's both a type and a variable? Also, it would mean your
code is interpreted differently if you forget an import statement.

The only feasible detection scheme is the pattern: a param looks like:
"identifier whitespace identifier" - wheras that pattern cannot
possibly indicate a legal expression.

v6ak

unread,
Oct 12, 2009, 10:19:38 AM10/12/09
to Project Lombok
I prefer type name because of its explicity and simple way to use
subclasses (or abstract implementations). However, I don't insist on
solution that I prefer, too.

I think that the nicest language that I know is Groovy. Is is a nice
language. Java is not as nice as Groovy, but it is IMHO better. I
think that #method(args){body} is more nice than
#InterfaceOrAbstractClassName(args){body}, but there are some
advantages that I wrote above.

BTW: I sometimes don't use arguments in method body. What about
omitting argument list in this case? Something like #Name(...){body}

Reinier Zwitserloot

unread,
Oct 12, 2009, 12:22:04 PM10/12/09
to Project Lombok
thought about allowing ommission of param list, but, between method
overloading throwing a wrench in the works*, the relative rarity of
not needing them, and the already quite complicated syntax, I thought
it better to not try and add that feature.

*) As a SAM has but one abstract method, this isn't an issue on the
surface. But what if we allow you to, say, create instances of
WindowAdapter quickly with something like:
#WindowAdapter.windowIconified(params) { code }? - Then overloading
could indeed cause issues. We could just error out with: Hey, that one
is overloaded, so you're going to have to add the parameters, so it's
not a big deal, but it is yet another complication.

Karsten Sperling

unread,
Oct 13, 2009, 11:10:04 PM10/13/09
to Project Lombok
I've been reading this discussion with a lot of interest; The
constructs currently supported by Lombok like @Getter/@Setter/@Cleanup
are great because they're simple and their meaning is obvious. It
would be great to have similarly simple support for non-transparent
closures (or what I would like to call _actual_ closures).

Please excuse me for getting back to basics, but a closure gets its
name from the fact that it "closes over" certain aspects of the
lexical environment (i.e. method) it is defined in; mostly this means
that it can access lexical variables from the enclosing scope, and
that those variables remain alive at least as long as the closure,
which can be longer than the particular activation of the enclosing
method that created the closure.

In this sense, 'transparent closures' aren't actually closures at all,
because they do NOT fully close over their enclosing scope, as they
only remain valid as long as that scope is active, because return/
break/continue become meaningless after that point (unless you are
proposing to add continuations as well). I think it would be more
meaningful to call these things 'code blocks', and not try to make
them interchangeable with closures (which map quite neatly to SAM
instances). This could probably be made to work by defining a separate
interface CodeBlock { void execute(); }, turning return/break/continue
into exceptions, and inserting code around the method invocation that
the block is passed to that catches these (Runtime-)Exceptions and
turns them back into the corresponding control flow action. E.g.
withLogging({ return 42; });
would become something like
try { withLogging(new CodeBlock() { void execute() { throw new
ControlFlowReturn(42); }; }); } catch (ControlFlowReturn e) { return
e.getReturnValue(); }

My main point here is not how this would work in detail, but that the
type for such a code block should be separate from any already
existing type like Runnable. I think the idea having a "do" modifier
on types that subtly (or not so subtly) perverts existing semantics is
horrible and counter-intuitive.

In fact I think it would be a huge step forward if Lombok supported
only non-transparent closures, and didn't support transparent code
blocks at all. Non-transparent closures are well understood and work
very well in lots of languages like Python, JavaScript, Lua to name a
few. Sure, you need the occasional workaround to pass on a return
value from a closure invocation as the return value of the outer
method, but I think non-transparent closures cover about 80-90% of use
cases very well, with none of the complexity and semantics changes
that a "first-order code blocks" model requires.

Karsten

Reinier Zwitserloot

unread,
Oct 14, 2009, 12:43:09 AM10/14/09
to Project Lombok
Hey Karsten,

Well, this theory sounds nice, but it's not very practical. Sure, you
can 'close over' local variables just fine, but what does 'closing
over' the current context (for return statements, throwing checked
exceptions, break, and continue) even mean, when the closure is long
gone? Unlike local variables, you can't keep elongate their existance
feasibly without adding continuations, and even with continuations,
its hard to just start one up, as you're effectively forking the
thread. Not to mention adding continuations to java would be quite a
feat.

So, that kind of closure view, which is in fact the view BGGA has
taken, just sucks, frankly. It seems nice, but it leads to a lot of
puzzlers, and a lot of confusion. Hence our focus on transparent
closures.

But, let's restrict ourselves to local variables for a sec. The nice
thing about local variables _right now_ in java is certain guarantees.
For example, you NEVER have to worry about thread issues if you have a
local reference pointing towards an immutable: The immutable, being
immutable, is not going to be a source of contention, and a local
variable can't possibly be shared with another thread, unless you make
it final. Introducing closures eliminates this rule, and that's a bad
thing. The unique bit is this: In our 'transparent closures' world
where we actually _guarantee_ that the closure couldn't possibly
escape the stack as it was when you defined the closure, you're right
back to this rule: no worries about thread contention and the variable
being modified from who knows where. You know exactly where and when
it'll be modified. This is nice. Yet another reason why making the
distinction is a valuable thing to do.


We were all about separating the transparent 'closures' with the
anonymous inner class literal syntax, but as the later posts in this
thread indicate, jpp, v6ak, and the other folks in this thread
convinced me that there's no good reason to separate the syntax that
much.

About naming conventions: Let's just not go there. The current
anonymous class literals are essentially real 'closures', with the
caveat that they refuse to close over non-final variables (but for
acceptable reasons, and you can always fake it with a final
AtomicReference), but whole hordes of closures fans are calling these
fake closures, because of various reasons (the 'only final variables'
distinction, the fact that they don't even try to support return/break/
continue transparency, and the fact that they must have a nominal type
have all been mentioned). Note that most of these distinctions are
flat out wrong in most senses. We could start a small didactic war
about what the term really means, but to be pragmatic about it: Let's
agree that 'closures' and 'code blocks' are effectively synonyms at
this point, simply because the majority of java programmers, if
they've heard of the terms at all, conflate the two.



Your suggestion about CodeBlock is utterly unworkable. Some of the
many fatal issues with it:

- no way to pass parameters to it, unless you generify the whole
thing, which is like BGGA's auto-generation of functional types, and
worse, in that it would suck with primitives which don't generify
nicely. Parameters are useful, because it allows the method that takes
the closure ('withLogging') to pass stuff to the closure.

- CodeBlock is an arbitrary name. The spirit of java favours nominal
over structural typing. This is more a beliefs kind of deal - I don't
like BGGA principally because it pisses on the idea of nominal typing.

- CodeBlock would still require compiler magic to ensure that any
method that takes a CodeBlock instance doesn't let it escape. *THAT*
would be counterintuitive - why does this type get magic treatment?
Especially considering that only lombok can apply the magic, so what
would happen if you write a method that takes a CodeBlock and compile
it with a non-lombok javac? If you try to compile a method that has a
'do' in front of a parameter, javac will just fail, unless you have
lombok on the classpath. Special magic rules means you should be using
a special keyword.

- You may be labouring under some wrong ideas about how this closure
proposal works: The 'do' modifier has nothing to do whatsoever with
types. The do modifier shows up on method parameters. So, the 1
parameter in this method signature: "public static <T> void sort
(List<T> list, do Comparator<? super T> comparator);" simply means
that this method will act exactly like the normal sort, except that it
*ALSO* can be called with a code block as second parameter. Type-wise,
there is zero difference in how this method works - it takes 1 list
and 1 comparator no matter how you call this code. This system can be
made backwards and forwards compatible, existing methods can be
retrofitted, but it IS an explicit marker, which is a good thing, for
various reasons already explained in this thread (such as: The code in
this method must not presume that invoking a method on the comparator
object can't possibly throw an undeclared checked exception).

- Making a new type means that you'd have to make an enormous amount
of new methods, which probably means a lot of method overloading, and
method overloading is evil and is going to screw up other lombok
ideas, such as named parameters, which really, really, _REALLY_
doesn't like method overloading. As we can't just change the java
runtime libraries, we'd have to do some sort of hack where we write
'macros' of sorts that translate an entirely new "public static <T>
void sort(List<T> list, CodeBlock<T, T, Integer> block) {}" back into
the real sort(List, Comparator) because java's rt.jar doesn't, of
course, have this method, and it would be ridiculous if any code
compiled with lombok requires a special lombok-rt.jar to work! We have
to work within the constraint that lombok needs to emit perfectly
legal, unencumbered class files that preferably have 0 dependency on
lombok.jar and definitely cannot rely on any of the crazy hacking
lombok does to work. You control your development environment, but
that can't be said for where your code ends up running.

- BGGA has the largest following of all closure proposals and they
make an excellent case for transparent closures. They are BY FAR the
most powerful part of closure proposals, in that you can roll your own
synchronized, foreach, logging, timing, lazily evaluating, (etc, etc)
implementations as a library. The only mistake camp BGGA has made is
to handwave away the massive amounts of complexity this entails as
inevitable, whereas our proposal says that by handing in 5% of the
power, you avoid half the complexity, and that this is totally worth
it.

Karsten Sperling

unread,
Oct 14, 2009, 2:05:33 AM10/14/09
to Project Lombok
Hi Reinier,

I don't disagree that transparent closures would be powerful -- but I
at least don't find that I miss them much. You're saying that with
your transparent closures, you'll get 95% of the power with 50% of the
complexity. I would say non-transparent closures give you 80% of the
power with 5% of the complexity. Being able to write e.g. Predicates
and Transformers concisely via lombok closures would be a huge benefit
to everyday code. And because as you say it's really just an anonymous
inner class, it's trivial to understand. Just like it's obvious what
@Getter does.

I don't see the thread contention issue as very relevant. In fact I
think it would be useful if the compiler were to promote locals that
are referenced read-write from a nested closure from being actual
locals to being public fields on a heap-allocated object, basically
the long-lived part of the stack frame. Sure, if you end up calling
the closure from multiple threads there can be contention, which the
programmer has to handle, but that is no different from accessing
fields of any other object that is shared between threads.

Your example of having to change the API to overload sort() to be able
to take a CodeBlock instead of a Comparator misses the point -- it
should only ever take a Comparator, which I would prefer to be able to
define via a nice closure syntax. But this would be a non-transparent
closure, and changing it to accept a transparent closure instead
doesn't make much sense -- what's a 'continue' in a comparator
supposed to do?

That's why I don't think it makes sense to say a function takes a "do
Comparator" parameter -- the contract for a comparator is that you can
pass it two values and get back their ordering, there's nothing in
that contract about doing non-local control flow like break/continue.
So if you need some new kind of transparent closure that you can pass
to e.g. doWithLogging(), then that should be a separate type that
specifies this contract, not "kind of a Runnable but you may get weird
exceptions popping out". The methods that take those closures would be
ones specifically written with that use-case in mind, like
doWithLogging() or foreach(), no existing APIs would need updating
with overloads.

I might add that for many of the examples like logging, timing, custom
synchronization, annotation-driven aspects provide quite neat
solutions. Sure, transparent closures may be useful in some cases, but
I see the bulk of the value for real-world code coming from the simple
non-transparent ones.

My main point wasn't to propose a solution for transparent closures,
but to say that transparent and non-transparent ones need some
conceptual distinction, and that most benefit can be had for a small
fraction of the complexity with just the non-transparent ones.

BTW I'm not sure I understood your comment about the compiler magic
correctly -- are you saying that you don't want to let any closures
escape from the scope they're defined in, i.e. not even support non-
transparent closures except as a special case of transparent ones?

Karsten

Reinier Zwitserloot

unread,
Oct 14, 2009, 2:39:02 AM10/14/09
to Project Lombok
But you can't write predicates and transformers concisely with just
Anonymous Inner Class Literals, because you can't throw checked
exceptions out of them, - or even do something as simple as breaking
off calculations the way a for loop can.

Moving the annotation that something has transparency to the type is
just wrong - The "Comparator" (an existing class, by the way!) in
Collections.sort is transparent, but the one in the TreeSet
constructor is not. Various methods that take Runnable are
transparent. Runnable's main (and arguably only proper) use,
java.lang.Thread, obviously isn't transparency safe. Documenting
transparent safety on the type is just completely the wrong place to
do it. That's a bit like documenting in, say, FileFilter, that you can
throw an IllegalStateException if you feel like it. Sure you can - but
you can do that everywhere.


You say that no existing API needs updating, but what about existing
API that works well with transparent closures? Collections.sort,
SwingUtilities.invokeAndWait, FileFilter, google collections API's
predicate based stuff (akin to foreach), and who knows how much code
in projects built with java that have code-in-code reuse issues (where
you repeat the start and end of a block of code many times, but the
middle is slightly different in each case. Depends on taste, but one
way to solve this is to pass the middle bit as 'closure' to 1 method
that contains the common intro and outro code).

We can quite easily create a system where you basically assert that
certain methods are 'closure-safe' (lombok should assume the parameter
has a 'do' in front of it, even if it doesn't). We CANNOT easily add
stuff to rt.jar.


We can't make everyone happy. you want us to split them up, others in
this thread were annoyed when that was the plan. So, we come to
concensus based on what seems like elegant design. We currently have a
scheme where


Here's why we aren't going to make a semantic distinction in the
syntax rules:

Because by historic proof, doing that doesn't help.

Closures are by their nature complex beasts. Java tried a _RIDICULOUS_
explicit syntax, having to name both type and method, and separating
out the entire issue of transparency and even requiring any closed-
over variables to be final, and people still get thoroughly confused
when they see an anonymous inner class literal. Clearly, throwing
multiple sentences worth of explicit syntax at the programmers doesn't
help them understand it any better.

Second reason: It _PROVABLY_ doesn't matter. If you write a
transparent closure that closes only over final variables, does not
use long return/break/continue, and throws no checked exceptions that
are illegal in the method you're overriding but are legal in your
outer scope, then there is absolutely no difference. It doesn't matter
if it is semantically a transparent closure or a non-transparent
closure; the end result is exactly the same, no matter how you inspect
this pseudo-class you just made. So why make a distinction in the
grammar?

Note that lombok can easily detect every single confusion between
transparency and non-transparency, and give helpful error messages for
every single case.


Example:

You're in a non-transparent closure, and you break. This break
resolves to a for loop that's outside your closure. If we make the
semantic distinction, the way anonymous inner class literals do, the
compiler will just go: Wahuh? and react the same way as if you stuck a
'break', without any other statements, in a new method. On the other
hand, lombok, by presuming transparency on parse, realizes you're just
confused and helpfully suggests that this isn't a transparent closure,
so if you meant to break into the enclosing for loop, you can't.

Same for continue, obviously.

Same, too, for throwing a checked exception that is legal in outer
scope but not legal in inner scope: Lombok can detect this and tweak
the error message.

Finally, we get to the last hurdle: "Return". Now, return in an
anonymous inner class literal currently always means 'inner return',
but I've personally witnessed this leading to some confusion. Because
the syntax is currently so awkward, it's fairly obvious you're in one,
and that helps, but we obviously don't want "giant mess of awkward
syntax" as an indicator, so that approach doesn't really scale.
Therefore, it's probably a good idea to demand that you write
"inner.return" even in a non-transparent closure, and we do the usual
thing if you attempt to write a plain return instead of an
inner.return: We tell you that you have to be specific. We can tweak
the error to be shorter, and just say: "use inner.return", when lombok
detects that you're in a non-transparent closure.

outer.return, then, is trivial - if we see that, we clearly know you
think you're in a transparent closure.


In all cases lombok can, after binding the method call and thus
knowing if this is a legal place for a transparent closure, either do
what the programmer clearly wants, or, give an error message that's
very specific.


That's win written all over it.


NB: We currently have a pretty much complete understanding of how our
closure proposal is going to work, including syntax. I'll write it up
at some point and post it for general perusal.

Jonathan

unread,
Nov 2, 2009, 2:58:30 PM11/2/09
to Project Lombok
I'm a bit late to the discussion, but since we're very interested in
Lombok and closures I wanted to throw my two cents in.

Overall, I lean towards keeping this simple. Any closure body could
simply be copied into the body of some generated method. There's no
need to introduce new keywords, assign new meaning to existing
keywords, allow semi-colons to be omitted, etc. Being able to explain
this as a simple block that is copied into a generated method is very
straightforward, and would certainly promote adoption.

With that said, I'm in favor of any sort of syntax that uses a block
enclosed in { }.

Collections.sort(stringList, { String a, String b => Integer.valueOf
(a.length()).compareTo(b.length()); });

Collections.sort(stringList, { String a, String b -> ... });

Collections.sort(stringList, (String a, String b) { ... });

Collections.sort(stringList, #(String a, String b) { ... });

Any of these are fine with me.

Regarding return values and returning control to the enclosing method,
I don't think this is an issue that should even be addressed.
Considering the simplest implementation as mentioned above, "return"
should simply return to the enclosing method. The only additional
meaning I am in favor of is CICE's proposal to have 'this' refer to
the enclosing object.

I do think we should support assignment of closures to some sort of
function type. I'm open to various syntax (BGGA, Scala, Groovy, etc)
to achieve this:

Jonathan

Reinier Zwitserloot

unread,
Nov 2, 2009, 3:48:37 PM11/2/09
to Project Lombok
Jonathan, I think your ideas run so counter to what Roel and I are
planning that it'll be hard to integrate any of them in what we're
working on. You're close to BGGA exactly in the areas where we chose
to deviate from it, and you are far away from BGGA exactly in the
areas where we chose to copy them. A small defense for some of our
choices:

A. The inner/outer return controversy: If you want to be able to
create control abstractions such as for each loops, synchronized,
etcetera, so that you can roll-your-own parallel loops, agent-like
frameworks, extended iterations, and the functional programming basics
of map and filter, you'll need outer returns. It's quite that simple.
How surprised would you be if you wrote a foreach loop that simply
loops until it finds something, then tries to return the result, only
for you to get a "your closure should return void" error?

B. syntax: We were already leaning towards #(params){code} which is
your third stated acceptable alternative syntax, so that should work
out well. To make lazy evaluating expressions easier we MAY allow
certain shorthands that avoid the param list altogether and have
optional braces provided you only need 1 expression in your code
block. You can do fun stuff with this, like, for example, the coalesce
function, which takes an arbitrary number of expressions and returns
the first one that returns a non-null value, WITHOUT evaluating any of
the expressions in the list that follow the first non-null value. It's
a small optimization that syntax-wise works out because single
expressions tend to be short.

C. 'this' referring to the inner object is virtually always useless,
so we were indeed planning on making 'this' refer to the first non-
closure-based object in the lexical stack (in simple situations, that
translates to 'the outer object').

D. Copying closure bodies around is something we thought of, but it
just doesn't work very well. Basically it can't be a closure (as in:
close over lexical scope) if you do that. How, exactly, do you copy
the variables used from the outer context to the code of the closure?
You can turn it on its head, and instead copy the code of the closure
method back into the place where you call the closure, but then you
get the same situation from the other end: The closure-accepting
method can now not use any of its own object's fields unless they are
public. There's also the issue of updates: If you update your library,
then any of the closure-accepting methods that you called don't get
updated because they are copies instead of actual calls.
> ...
>
> read more »

Jonathan

unread,
Nov 2, 2009, 7:02:17 PM11/2/09
to Project Lombok
Reinier,

Reading back through this thread again, we're in line with each others
thinking on many things, but not on the return keyword. Since
(presumably) the majority of newly written closures will be non-
transparent, my primary concern is that these should be supported
without changing the meaning of existing keywords or requiring new
keywords (such as inner.return). Regarding access to variables from
the enclosing scope, something like the CICE proposal seems reasonable
to me.

For transparent closures, I understand the need for the solutions
you're looking at such as new keywords or meta information, but I
don't think it should come at the expense keeping non-transparent
closures simple.

There are a things regarding syntax that were mentioned in this thread
which I wanted to go over again. Re: inline syntax:

someMethod(param, #(){ // do something });

Could this not be shortened to:

someMethod(param, #{ // do something });

Re: inlining closures to fulfull a method parameter, a return keyword
should only be required if the SAM for the parameter being fulfilled
does not return void:

Collections.sort(stringList, #(String a, String b) {
return Integer.valueOf(a.length()).compareTo(b.length()); // return
required
});

new Thread(#{
System.out.println("Starting thread"); // no return needed
}).start();

Finally: Some assignment syntax:

Runnable runnable = #{
// do something
};

Comparable comparable = #(String a, String b) {
return Integer.valueOf(a.length()).compareTo(b.length());
};


jonathan
> ...
>
> read more »

Reinier Zwitserloot

unread,
Nov 2, 2009, 7:46:24 PM11/2/09
to project...@googlegroups.com
I think we left this discussion with the following conclusion:

(General rule: A closure literal is legal ONLY as a method argument if it is to be transparent. If it appears anywhere else, it is by definition not eligible for becoming a transparent closure).

1. *IF* returns are always explicitly specified as inner.return or outer.return, and *IF* the break/continue behaviour of a closure is always specified in a way that is obvious from the site where you declare a closure, then:

 1A. whether or not a closure is supposed to be transparent is obvious from just looking at the closure, *EVEN IF* the type that your closure is supposed to conform to is not found by the compiler.

 1B. The closure is idempotent - you can move it around, and the meaning of any return, break, continue, throw, etc statements doesn't change. In fact, whether its transparent or not doesn't change either.

These are both great things to have, and the caveats are worth it, so, as is, we are planning to:

- Either forget about closure-local for-like behaviour (which would allow you to rebuild foreach as a closure-accepting API call instead of a language feature), or enforce the need to state this fact BOTH at the method-accepting closure AND at the closure literal level.

- Force usage of inner.return or outer.return (or whatever syntax we end up for this), even in non-transparent closures.

- Have absolutely no indicator of whether a closure is transparent or not. It will be if you are doing things which clearly require it to be, it won't be if you don't. In practice, you can do whatever you want in a closure, and if it's going to lead to problems (such as long-breaking out of an event listener), then you get a compiler error that explicitly states that the action you are doing requires transparency which the context doesn't allow.

2. Transparency is a worthy goal, and more importantly, without transparency, the most vocal closure fans of java (which pretty much all like BGGA), will not like this proposal. Making lombok popular is a stated goal of lombok, therefore, it is a stated goal of lombok's closure proposal. This makes transparency an even more worthy goal, and thus worth wrestling through the annoyances that go with it. However, with escape detection analysis, the runtime annoyances are kept to a minimum, which only leaves syntactic annoyances, which are limited pretty much _only_ to the return statement.

Thus:

- Lombok closures WILL support transparency.

- Lombok guarantees preservation of the execution stack frame as long as a closure may be run. This rule causes a few simple restrictions that BGGA doesn't have, but pays out by being vastly simpler. e.g: Can't let your closure escape, _BUT_, no 'throws E' generics parameters either.

- Lombok MUST somehow solve the return statement issue.

3. Full transparency, such that statements like "return foo;" do not change meaning when turning a code block into a closure, is nice but not an absolute goal. Therefore, just "return foo;" meaning: "return from inner closure" is not by default off the table. However, the 'default obvious action' for a return statement depends entirely on the method you're giving your closure to - if you're calling an ARM-like guard block, then clearly return is supposed to mean outer return, but if you're calling Collections.sort, clearly it means inner return. As, due to the first design rule, closures must not change meaning depending on where you place them, lombok closures cannot 'magically do the right thing' - mostly because too much magic is bad.

thus:

- "return foo;" is too ambiguous to be given a default, which is why the proposal as is always errors when you try and asks you to pick one - 'inner.return' or 'outer.return' - or whatever syntax we come up with.

- Technically, you can wrap closures in closures in closures, which means "outer.return" is ambiguous. This problem already exists in java for break and continue statements, which was solved with labels. We may have to do the same thing, leaving 'inner' and 'outer' as aliases for the innermost level, and the outermost (method) level, respectively.

4. Structural typing (letting the type of e.g. #(String a, String b) { inner.return 5;} be Function<String, String, Integer>) doesn't mesh well with java, and is not necessary for closure proposals. Therefore, lombok's closure proposal will not include them. Perhaps more strikingly: structural typing is IMPOSSIBLE to do without JVM support OR generating lots of code files in default locations, which don't really exist in the contexts lombok runs in, thus, the point is kind of moot - if lombok is to actually give you an in-production-usable closure implementation, structural types cannot be a part of it.

thus:

- all closure blocks must ALWAYS be targeted; they must appear on the RHS of an assignment or as a method argument so that the type of the method argument or the type of the LHS of the assignment is a SAM type - that way the closure block can be typed according to that.




Everything has its disadvantages. In particular, the 'magic' route, where break, continue, and return just 'do the right thing' depending on the method you're passing the closure to, possibly even using the method you're passing the closure to as source for whether the closure is to be transparent or not, seems easier for various use cases. However, it's a lot more complex and downright confusing for others, so it's always a trade-off. However, being consistent (EITHER being totally dependent on the method you're passing the closure to, OR being totally INdependent of the method you're passing the closure to) is a good thing, and the independent route seemed to have less seriously ugly / confusing use cases than going the dependent route.

--Reinier Zwitserloot

Jonathan

unread,
Nov 2, 2009, 8:49:34 PM11/2/09
to Project Lombok
I don't think "return foo" has to be ambiguous when dealing with a non-
transparent closure. The meaning of "return" could always be
return.inner and allowed for the benefit of non-transparent closures
and those who write them.

jonathan
> ...
>
> read more »

Reinier Zwitserloot

unread,
Nov 2, 2009, 11:09:00 PM11/2/09
to project...@googlegroups.com
Ah, but, the entire point is that there's no difference between transparent and non-transparent closures. Lombok figures out which one you meant by analysing what you do. This requires the return statement to be obvious. - it needs to figure out what that means BEFORE it can figure out if this is a transparent closure or not.

We could technically work around this by leaving an unqualified return in a limbo state until we do know, and we might do that, but it does sort of take away from the elegance of having transparent closures that don't use any of the features that _require_ transparency be completely equal to non-transparent closures. (In that, with your suggestion, inner.return would be neccessary if the closure is transparent, but just 'return' would work fine if it wasn't).

--Reinier Zwitserloot
Reply all
Reply to author
Forward
0 new messages