Help us brainstorm closure syntax.

106 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