Good gosh J7 lambdas/closures are looking worse by the day

42 views
Skip to first unread message

Michael Neale

unread,
May 31, 2010, 1:58:01 AM5/31/10
to The Java Posse
http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-of-closures/comment-page-1/#comment-2023

I guess most of the attention has been on the semantics (and rightly
so) but wow... just wow.

(sorry to interupt the appleposse with java news).

Mark Derricutt

unread,
May 31, 2010, 2:07:31 AM5/31/10
to java...@googlegroups.com
I realllllly don't like the look of them.  If they'd reused { } around the actual method call I'd be much happier.  But reusing ()?


--
Pull me down under...

--
You received this message because you are subscribed to the Google Groups "The Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.


Russel Winder

unread,
May 31, 2010, 2:21:11 AM5/31/10
to java...@googlegroups.com

Is there a page with the proposal set out? Have the authors of the
earlier proposals written up anything about this?

--
Russel.
=============================================================================
Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel...@ekiga.net
41 Buckmaster Road m: +44 7770 465 077 xmpp: rus...@russel.org.uk
London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder

signature.asc

Reinier Zwitserloot

unread,
May 31, 2010, 6:08:52 AM5/31/10
to The Java Posse
Here's a very short rundown on the official syntax, with a link to the
last known proposal at the end. The current status quo isn't, as far
as I know, 100% the same as the 'official' proposal, because a new
version of the spec hasn't been released in months. There's also been
an encyclopedia's worth of traffic on concerns and disadvantages on
lambda-dev, but none of those have been discussed by Mark Reinhold,
Alex Buckley, Maurizio Cimadamore, or Brian Goetz, who all seem to be
involved in writing specs and implementations.

closures themselves come in two flavours. Either form is an
expression, whose type is a closure type:

inline expression form:

#(parameter list) ( expression )

block form:

#(parameter list) { any number of statements; }


The first form is syntax sugar for:

#(parameter list) { return expression; }


So, you can write:

Object plusClosure = #(int a, int b) (a+b);

which is the same thing as writing:

Object plusClosureLongForm = #(int a, int b) {return a + b;};

[Justification: In practice blocks have to be written in standard
style, so, line breaks after opening brace and before closing brace,
lest it look like a semi-colon party, but that means all closures are
multi-line, even very simple ones, such as plus, so, there's a short-
hand form if you can express the body of a closure as a single
expression. Also, inferring parameters is essentially impossible but
inferring return type and checked exceptions isn't, and closures
should be simple (and syntactically very brief), hence the inference.]

Note that 'long returns' doesn't work, you can't break or continue a
loop that your closure definition is in, nor can you return from the
method that your closure definition is in.

Also, the closure captures all variables from outer scope but you
can't actually interact with them unless they are final or effectively
final (effectively final = not marked final, but wouldn't cause an
error if they were marked as such).

The full type signature of a closure consists of 3 properties:

A) Parameter List. Read from the actual parameter list in the closure
definition.
B) Return Type. Inferred from the return statement (block form) or the
type of the expression (inline expression form)
C) (checked) throwables thrown. Inferred.

Obviously assigning a closure to an "Object" variable isn't very
useful. There are two useful type concepts you can assign them to,
function types and SAMs.

Function Types. These look like this:

#int(int, int)(throws IOException | SQLException) plusClosure = #(int
a, int b) (a+b);

[yes, good lord, that's some horrible syntax, I know - also the
official 1.5 spec on function syntax is riddled with errors particular
in regards to the throws syntax; alternatives that also might be valid
depending on where you look in the spec is "(throws IOException,
SQLException)" and just "(IOException, SQLException)".

justification: Without the extra parens around the throws clause the
parsing rule wouldn't terminate which isn't legal in LL(k) grammars
such as the ones used by most java parsers including javac. Or
something. I was a bit fuzzy on this, you may want to check lambda-
dev.]

function types can be 'executed' by using the dot. For example:

assert 15 == plusClosure.(5, 10);

[justification: In java, method names and variable names are separate
namespaces, so just closureVarName() would be looking in the wrong
namespace!]

Closures can also be assigned to SAM types. A SAM type is any type
that is (1) abstract and (2) has only one undefined method in it. In
other words, any interface that mentions only 1 method, and any
abstract class where all but 1 method has an implementation. Like
FileFilter and Runnable. Thus, this would work just fine:

Runnable r = #() {System.out.println("Hello, World!");};
r.run(); //Will say hi to world.
r.(); //This wouldn't be legal; r is a Runnable, not a #()().

The mechanics for realizing that the above closure declaration, which
is of type #()(), can be 'fitted' safely into a java.lang.Runnable
SAM, requires lots of complex inference rules. This inference includes
the reasoning that returning something is compatible with returning
nothing, an inference that doesn't occur anywhere else in java. E.g:

#void(Integer a) = #(Number a) (a);

is legal. If you throw enough generics in the mix, the errors are
going to balloon into gobbledygook. Nevertheless, SAMs are what
today's java libraries run on, so any closure proposal that cannot
'autobox' themselves into a SAM type would be even worse.


"this" in a closure refers to the closure object. This seems nuts but
has been added for the benefit of allowing closures to recurse into
themselves. However, you'd get an endless loop when trying to infer
return type if you actually returned 'this', so the following is
explicitly defined as a compiler error:

Object closure = #() (this); //Infer the return type on this miracle!



The actual way closure types are created most likely will involve
generics of some sort, so arrays of closure types, like so:

#()[] = new #()[10];

aren't legal for the same reason you can't write new T[10];


Link: http://mail.openjdk.java.net/pipermail/lambda-dev/attachments/20100212/af8d2cc5/attachment-0001.txt


On May 31, 8:07 am, Mark Derricutt <m...@talios.com> wrote:
> I realllllly don't like the look of them.  If they'd reused { } around the
> actual method call I'd be much happier.  But reusing ()?
>
> --
> Pull me down under...
>
> On Mon, May 31, 2010 at 5:58 PM, Michael Neale <michael.ne...@gmail.com>wrote:
>
>
>
>
>
> >http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-o...
>
> > I guess most of the attention has been on the semantics (and rightly
> > so) but wow... just wow.
>
> > (sorry to interupt the appleposse with java news).
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "The Java Posse" group.
> > To post to this group, send email to java...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > javaposse+...@googlegroups.com<javaposse%2Bunsubscribe@googlegroups .com>
> > .

Casper Bang

unread,
May 31, 2010, 6:49:12 AM5/31/10
to The Java Posse
Wow that's ugly. Source code obfuscaters are going to have a blast.

Roel Spilker

unread,
May 31, 2010, 8:46:29 AM5/31/10
to java...@googlegroups.com
> Closures can also be assigned to SAM types. A SAM type is any type that is (1) abstract and
> (2) has only one undefined method in it.
> In other words, any interface that mentions only 1 method, and any abstract class where all
> but 1 method has an implementation. Like FileFilter and Runnable.

If an interface declares methods already defined in Object, they don't count either...

For instance, the interface java.util.Comparator has two methods:

int compare(T o1, T o2);
boolean equals(Object obj);

The second method is in there because it has some javadoc on it. Since Object has a method with the same signature, Comparator still qualifies as a SAM.

Roel

Josh McDonald

unread,
May 31, 2010, 10:46:28 PM5/31/10
to java...@googlegroups.com
Ew, this reeks of "making the compiler-writer's job easy". There must be a nicer solution, even within the narrow guidelines of the problem. Even Obj-C's blocks are nicer than this (in Syntax at least).

--
You received this message because you are subscribed to the Google Groups "The Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.




--
"Therefore, send not to know For whom the bell tolls. It tolls for thee."

Josh 'G-Funk' McDonald
  -  jo...@joshmcdonald.info
  -  http://twitter.com/sophistifunk
  -  http://flex.joshmcdonald.info/

Michael Neale

unread,
Jun 1, 2010, 1:12:23 AM6/1/10
to The Java Posse
I think it shows it in its worst light, when others show examples it
is OK I guess...

I guess I am more interested in the semantics given that other
languages are far more useful to me (and interesting as well) thus
interop matters if this will be used in JDK apis. Otherwise it is
really hard to care.

On Jun 1, 12:46 pm, Josh McDonald <j...@joshmcdonald.info> wrote:
> Ew, this reeks of "making the compiler-writer's job easy". There must be a
> nicer solution, even within the narrow guidelines of the problem. Even
> Obj-C's blocks are nicer than this (in Syntax at least).
>
> On 31 May 2010 15:58, Michael Neale <michael.ne...@gmail.com> wrote:
>
>
>
>
>
>
>
> >http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-o...
>
> > I guess most of the attention has been on the semantics (and rightly
> > so) but wow... just wow.
>
> > (sorry to interupt the appleposse with java news).
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "The Java Posse" group.
> > To post to this group, send email to java...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > javaposse+...@googlegroups.com<javaposse%2Bunsubscribe@googlegroups .com>
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/javaposse?hl=en.
>
> --
> "Therefore, send not to know For whom the bell tolls. It tolls for thee."
>
> Josh 'G-Funk' McDonald
>   -  j...@joshmcdonald.info

Josh McDonald

unread,
Jun 1, 2010, 1:25:11 AM6/1/10
to java...@googlegroups.com
Agreed, I'm far more interested in the JVM having a standard "function" type and invocation semantics than the syntax within Java source.

To unsubscribe from this group, send email to javaposse+...@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.




--
"Therefore, send not to know For whom the bell tolls. It tolls for thee."

Josh 'G-Funk' McDonald
  -  jo...@joshmcdonald.info

Moandji Ezana

unread,
Jun 1, 2010, 4:35:26 AM6/1/10
to java...@googlegroups.com
On Tue, Jun 1, 2010 at 7:12 AM, Michael Neale <michae...@gmail.com> wrote:
I think it shows it in its worst light, when others show examples it
is OK I guess...

I agree, I don't think they're particularly ugly. Taking a simple, but real, example:

List<String> userNames = userList.map(#(User u) {
  u.getName();
});

I can't see anything so terrible or unreadable about that.

Moandji

Kevin Wright

unread,
Jun 1, 2010, 4:56:01 AM6/1/10
to java...@googlegroups.com
Syntax wise, we can be a lot smarter by moving to another JVM language:

  val userNames = userList.map(_.name)
or
  val userNames = userList map _.name 

(both valid Scala)

So I'm definitely in the group here that's behind making this standardised at the bytecode level.  The overriding need for backward compatibility just makes it impossible to do anything truly elegant in Java, but this can just be considered a mere triviality nowadays.


--
You received this message because you are subscribed to the Google Groups "The Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.



--
Kevin Wright

mail/google talk: kev.lee...@gmail.com
wave: kev.lee...@googlewave.com
skype: kev.lee.wright
twitter: @thecoda

B Smith-Mannschott

unread,
Jun 1, 2010, 6:54:36 AM6/1/10
to java...@googlegroups.com

hhmmm...

wouldn't that be

List<String> userNames = userList.map(#(User u)(
u.getName() // note: round parens, no ";", implicit "return"
));

or

List<String> userNames = userList.map(#(User u){

return u.getName(); // note: "return"
});

But yea, it's not so bad, considering that it's Java.

// Ben

Reinier Zwitserloot

unread,
Jun 1, 2010, 7:28:12 AM6/1/10
to The Java Posse
A clarifying comment by Maurizio on lambda-dev claims that they are
currently implementing something that's similar to the straw man
presented by Mark Reinhold at Devoxx '09, with some of the tough
questions in it removed (such as using .() instead of plain parens to
'execute' a closure), so the widespread discussion on lambda-dev can
at least experiment better.

In otherwords, 'making the compiler-writer's job easy' is apparently
part of the plan, at least for now.

A standard function type in the JVM *already exists* in the jdk7
specs; it's called MethodHandle. There are already calls going out
amongst the alternative languages on the JVM crowd to start switching
to it. Also, partly motivated by the closures stuff, MethodHandle
objects will most likely gain a JVM-based 'asSam()' method which means
at least some of the structural typing that other languages offer can
be done 'natively' instead of working by using a lot of reflection
magic. So, Josh, Michael, time to lobby your friendly local
alternative language developer to get on the bandwagon :)

On Jun 1, 4:46 am, Josh McDonald <j...@joshmcdonald.info> wrote:
> Ew, this reeks of "making the compiler-writer's job easy". There must be a
> nicer solution, even within the narrow guidelines of the problem. Even
> Obj-C's blocks are nicer than this (in Syntax at least).
>
> On 31 May 2010 15:58, Michael Neale <michael.ne...@gmail.com> wrote:
>
>
>
>
>
>
>
> >http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-o...
>
> > I guess most of the attention has been on the semantics (and rightly
> > so) but wow... just wow.
>
> > (sorry to interupt the appleposse with java news).
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "The Java Posse" group.
> > To post to this group, send email to java...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > javaposse+...@googlegroups.com<javaposse%2Bunsubscribe@googlegroups .com>
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/javaposse?hl=en.
>
> --
> "Therefore, send not to know For whom the bell tolls. It tolls for thee."
>
> Josh 'G-Funk' McDonald
>   -  j...@joshmcdonald.info

Reinier Zwitserloot

unread,
Jun 1, 2010, 7:30:26 AM6/1/10
to The Java Posse
Almost, Moandji. This would be the syntax you're looking for in this
particular example:

List<String> userNames = userList.map(#(User u) (u.getName()));

Or, alternatively (both are legit):

List<String> userNames = userList.map(#(User u) {
return u.getName();
});

If I put them in a bad light, I apologize - that wasn't my intent. My
intent was to simply state the proposal, and inject a little despair
into the crazy syntax for function -types-. The syntax for the
closures themselves is fine, and, in fact, one of the few that really
works well with existing java style guides (braces imply newlines,
etc).

On Jun 1, 10:35 am, Moandji Ezana <mwa...@gmail.com> wrote:

Reinier Zwitserloot

unread,
Jun 1, 2010, 7:32:38 AM6/1/10
to The Java Posse
Oh, yeah, we'll just move every single existing java programmer over.
Easy peasy.

I get really annoyed at people who have this 'oh, give up java
already' vibe. If you don't care, that's fine. Why don't you go and be
positive on the scala mailing list, instead of being negative here?
Some of us are trying to make java a better language. If you'd rather
torch java's future to increase scala adoption, I don't want to talk
to you. The more languages the merrier, let them win on their merits,
not by the demerits of other languages. Also, it's all on the JVM.
When one JVM language gains strength, that solidifies the JVM as a
platform, which is good for all JVM languages. I want a strong Scala
*AND* a strong Java.
> > javaposse+...@googlegroups.com<javaposse%2Bunsubscribe@googlegroups .com>
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/javaposse?hl=en.
>
> --
> Kevin Wright
>
> mail/google talk: kev.lee.wri...@gmail.com
> wave: kev.lee.wri...@googlewave.com
> skype: kev.lee.wright
> twitter: @thecoda

Kevin Wright

unread,
Jun 1, 2010, 8:41:05 AM6/1/10
to java...@googlegroups.com

Quite the opposite, I want to promote java-the-platform vs .net, ruby, etc.

Java is a great language if you want compatibility all the way back to 1.0 code, but in terms of having contemporary features and being fun to use it's already lost a great deal of mindshare.

Scala is, frankly, the lowest impact change for java developers willing to move to a better integrated functional syntax (at the cost of legacy functionality)

I *could* promote Java by defending an outdated legacy syntax that must be kept for reasons of backward-compatibility.  I could also promote Star Trek by shouting down anyone who says that Kirk's character is over-acted.  But to me, the true essence of Star Trek is perhaps better captured with Patrick Stewart at the helm...

And so it is with Java vs Scala, we may mourn the loss of mini-skirts from time to time (who doesn't?).  Nevertheless, the end product is arguably better, and you have to admit that holo-decks are pretty cool - there are many stories that just wouldn't have been written without them (a bit like built-in FP then).

So did Star Trek NG denigrate the original series?  I'd like to think not - it's full of nostalgia for me.  I'd also like to think that Scala isn't denigrating Java, it's just the future of the same universe.


As for Scala mailing lists?  Yes, I'm a frequent contributor there, where they boldly go to some amazing new places at times.  The best part is that we manage to do so without the dilithium crystals failing every third episode, and I'm finding that I really don't miss it as a plot element all that much.


On 1 Jun 2010 12:32, "Reinier Zwitserloot" <rein...@gmail.com> wrote:

Oh, yeah, we'll just move every single existing java programmer over.
Easy peasy.

I get really annoyed at people who have this 'oh, give up java
already' vibe. If you don't care, that's fine. Why don't you go and be
positive on the scala mailing list, instead of being negative here?
Some of us are trying to make java a better language. If you'd rather
torch java's future to increase scala adoption, I don't want to talk
to you. The more languages the merrier, let them win on their merits,
not by the demerits of other languages. Also, it's all on the JVM.
When one JVM language gains strength, that solidifies the JVM as a
platform, which is good for all JVM languages. I want a strong Scala
*AND* a strong Java.


On Jun 1, 10:56 am, Kevin Wright <kev.lee.wri...@gmail.com> wrote:

> Syntax wise, we can be a lot s...

> On 1 June 2010 09:35, Moandji Ezana <mwa...@gmail.com> wrote:
>
>
>
>
>
> > On Tue, Jun 1, 2010 at 7:12 AM, Michael Neale <michael.ne...@gmail.com>wrote:

>
> >> I think it shows it in its worst light, when others show examples it
> >> is OK I guess...
>

...

> > javaposse+...@googlegroups.com<javaposse%2Bunsubscribe@googlegroups .com>

> > .
> > For more options, visit this group at
> >http://groups.google.com/group/javaposse?hl=en.

>...

> mail/google talk: kev.lee.wri...@gmail.com
> wave: kev.lee.wri...@googlewave.com

> skype: kev.lee.wright
> twitter: @thecoda

--
You received this message because you are subscribed to the Google Groups "The Java Posse" group...

Peter Becker

unread,
Jun 1, 2010, 4:46:31 AM6/1/10
to java...@googlegroups.com
Serious question (still trying to get my head around the syntax, but too busy (i.e. lazy) to look it up):

Shouldn't this be either


  List<String> userNames = userList.map(#(User u) {
    return u.getName();
  });

or

  List<String> userNames = userList.map(#(User u)(u.getName());

? I thought the curly brace variants requires a proper Java method body. Or did I get that wrong?

I don't mind that first variant, the variant with the single expression is a bit high on parentheses overload for my taste.

   Peter

Alexey Zinger

unread,
Jun 1, 2010, 2:04:33 PM6/1/10
to java...@googlegroups.com
So basically, this is just syntax sugar around single-method anonymous inner classes.  I'm not saying it's the end of the world, but they aren't closures strictly speaking.  Everything I ever read about what differentiates closures from anonymous inner classes (control flow, lexical scoping) is untouched as compared to what we do already with more verbose syntax.
 
Alexey
2001 Honda CBR600F4i (CCS)
2002 Suzuki Bandit 1200S
1992 Kawasaki EX500
http://azinger.blogspot.com
http://bsheet.sourceforge.net
http://wcollage.sourceforge.net



From: Reinier Zwitserloot <rein...@gmail.com>
To: The Java Posse <java...@googlegroups.com>
Sent: Mon, May 31, 2010 6:08:52 AM
Subject: [The Java Posse] Re: Good gosh J7 lambdas/closures are looking worse by the day
> > javaposse+unsub...@googlegroups.com<javaposse%2Bunsubscribe@googlegroups .com>

> > .
> > For more options, visit this group at
> >http://groups.google.com/group/javaposse?hl=en.

--
You received this message because you are subscribed to the Google Groups "The Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+unsub...@googlegroups.com.

Casper Bang

unread,
Jun 1, 2010, 2:41:15 PM6/1/10
to The Java Posse
On Jun 1, 8:04 pm, Alexey Zinger <inline_f...@yahoo.com> wrote:
> So basically, this is just syntax sugar around single-method anonymous inner classes.  I'm not saying it's the end of the world, but they aren't closures strictly speaking.  Everything I ever read about what differentiates closures from anonymous inner classes (control flow, lexical scoping) is untouched as compared to what we do already with more verbose syntax.

Yeah that was my conclusion as well; that we will have to continue to
put variables into a one-dim array in order to hoist it from stack to
heap and avoid the annoying "final limitation". This does not match
Neal Gafter's definition of a closure. Or did I misunderstand?

Kevin Wright

unread,
Jun 1, 2010, 3:07:58 PM6/1/10
to java...@googlegroups.com
Sadly not, from my understanding of the proposal :(

What really counts though is that we get 1st-class method handles.  That then allows interop between the various JVM languages, as well as any "hoisting" technique in the book (including compiler-generated approaches used by Scala, Clojure, et. al.)

When we consider that Java was able to add both inner classes and generics without changing the bytecode, you get a better feel of what innovation might be possible on to of this minor addition...

--
You received this message because you are subscribed to the Google Groups "The Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.




--

Moandji Ezana

unread,
Jun 1, 2010, 3:50:58 PM6/1/10
to java...@googlegroups.com
I apologise to all for forgetting the return keyword. It was a quickly-written email using a language feature I'd spent a total of 5 minutes looking at. My point was just that it's not too ugly if you space it out a little. That said, I'm one of those people who don't get what the big deal is about removing semi-colons.

So basically, this is just syntax sugar around single-method anonymous inner classes.

Is that such a bad thing? What would, for example, control flow make possible that couldn't be done otherwise?

What really counts though is that we get 1st-class method handles.

Agreed. That's pretty awesome. Also, the prospect that the VM might be able to make dynamic languages as fast or nearly as fast as static ones.

the annoying "final limitation"

What's the actual reason for this? It's so easy to get around that it doesn't seem like it should exist at all. 

Moandji

Kevin Wright

unread,
Jun 1, 2010, 4:07:33 PM6/1/10
to java...@googlegroups.com
On 1 June 2010 20:50, Moandji Ezana <mwa...@gmail.com> wrote:

What really counts though is that we get 1st-class method handles.

Agreed. That's pretty awesome. Also, the prospect that the VM might be able to make dynamic languages as fast or nearly as fast as static ones.


Hopefully, though the big win for dynamic languages here is invokedynamic, not method handles.

It's also worth noting that all of the general purpose JVM languages (except Java) already have some form of closure, whether dynamically (JRuby, Groovy) or statically typed (Scala), and performance in the space is pretty damn good.  The significant gain then is not in performance, but in interop between them all.


 

Casper Bang

unread,
Jun 1, 2010, 4:27:58 PM6/1/10
to The Java Posse
> What's the actual reason for this? It's so easy to get around that it
> doesn't seem like it should exist at all.

Inner classes never really access the local variable, but rather a
snapshot of it taken at the time the class was instantiated and passed
along to a new stack frame. That was how it originally got
implemented, probably for performance reasons since they were meant
for specifying callbacks to UI libraries (Instead of native events/
delegates/methods-pointers) and the heap is a lot more expensive to
access than the stack?!

Alexey

unread,
Jun 1, 2010, 4:33:18 PM6/1/10
to The Java Posse
On Jun 1, 3:50 pm, Moandji Ezana <mwa...@gmail.com> wrote:
> > So basically, this is just syntax sugar around single-method anonymous inner
> > classes.
>
> Is that such a bad thing? What would, for example, control flow make
> possible that couldn't be done otherwise?

To me, it's not so much a question of good or bad at this point, but
what we're actually getting. When CICE and BGGA discussions were
happening, things like non-local control flow were explicitly
discussed:
* http://www.javac.info/closures-v05.html
* http://www.javac.info/bloch-closures-controversy.ppt

As a quick realistic example, suppose you want to support resource
closing using a Closeable interface. With Java 7 syntax, you might
write something akin to this:

public static void withResource(Closeable resource, #() block)
{
block.();
resource.close();
}

and somewhere else:

// let's imagine that SQLConnection implements Closeable
SQLConnection conn = ...;
withResource(conn, #() {
// do stuff
});

Swell, except, it turns out SQLConnection.close() might throw
SQLException. How do we express that and how does it fit in the flow
of control? If it was a true closure, the definition of withResource
would not change, because the enclosing block (the code that calls it)
would be able to handle exceptions that come out of the closure. But
in our current situation, we have to express this notion that
SQLException's implementation of close has to throw some kind of
exception as part of the type of the "closure" (bring on the throws
type variance hell) and subsequently in withResource implementation.
This significantly muddies the waters.

Now, don't get me wrong, I think this will be useful and we'll get
plenty done with it. But what I'm saying here is that this gives us
very little that we don't already have. This is just syntax on top of
already existing patterns. Yes, it'll make code prettier and probably
more readable in most cases, but the boat on the big gains either has
long sailed or was never in the harbor to begin with.

Colin Decker

unread,
Jun 1, 2010, 4:30:21 PM6/1/10
to java...@googlegroups.com
From my understanding it's planned to allow the use of non-final local variables in lambdas, though they may have to be marked with a keyword like "shared" or an annotation @Shared to indicate the intent. See "Type 3 lambdas - functions capturing mutable state" in the initial translation document draft: http://cr.openjdk.java.net/~mcimadamore/lambda_trans.pdf.

Colin

--
You received this message because you are subscribed to the Google Groups "The Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.

Reinier Zwitserloot

unread,
Jun 1, 2010, 9:40:38 PM6/1/10
to The Java Posse
Learning java closure syntax is more complicated than learning scala?
You've got to be kidding me.

Reinier Zwitserloot

unread,
Jun 1, 2010, 9:46:13 PM6/1/10
to The Java Posse
They DO capture all variables from lexical scope. They then add the
compiler limitation where the compiler will understand what you mean
but refuse to compile it if you access a mutable local variable. For
good reasons.

control flow, if I can presume you mean "long" returns / breaks /
continues, have been left out for now because they can most easily be
added later, and are a gigantic source of complexity.

(think about it - what happens when you 'long return' out of a method
that's already long exited, because the closure has been stored in a
field someplace and executed later? Or, what should happen if a
closure that is run in another thread tries to 'break' out of a still
running for loop? That for loop is now running in another thread
compared to the closure, so - should two threads dovetail their way
through a for loop? That's going to be hard to make work! In practice
you need to add the notion of 'unescaping' closures to either the type
system or the compiler's analysis. You see how the complexity starts
adding up quickly).

You're technically right in that the term 'closure' is being slightly
overextended here. However, just like "HTML5" doesn't actually mean
you use features from the HTML5 spec, "AJAX" does not mean you use XML
(or even an XmlHttpRequest object), and "javascript" has nothing to do
with "java", terms in the programming world change meaning all the
time. In java land, "closures" currently means "code blocks". I'll
join you in lamenting the loss of clarity caused by this confusion,
but, it happened. No way to put this genie back in its box.

On Jun 1, 8:04 pm, Alexey Zinger <inline_f...@yahoo.com> wrote:
> So basically, this is just syntax sugar around single-method anonymous inner classes.  I'm not saying it's the end of the world, but they aren't closures strictly speaking.  Everything I ever read about what differentiates closures from anonymous inner classes (control flow, lexical scoping) is untouched as compared to what we do already with more verbose syntax.
>
>  Alexey
> 2001 Honda CBR600F4i (CCS)
> 2002 Suzuki Bandit 1200S
> 1992 Kawasaki EX500http://azinger.blogspot.comhttp://bsheet.sourceforge.nethttp://wcollage.sourceforge.net
>
> ________________________________
> From: Reinier Zwitserloot <reini...@gmail.com>
> Link:http://mail.openjdk.java.net/pipermail/lambda-dev/attachments/2010021...
>
> On May 31, 8:07 am, Mark Derricutt <m...@talios.com> wrote:
>
>
>
>
>
> > I realllllly don't like the look of them.  If they'd reused { } around the
> > actual method call I'd be much happier.  But reusing ()?
>
> > --
> > Pull me down under...
>
> > On Mon, May 31, 2010 at 5:58 PM, Michael Neale <michael.ne...@gmail.com>wrote:
>
> > >http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-o...
>
> > > I guess most of the attention has been on the semantics (and rightly
> > > so) but wow... just wow.
>
> > > (sorry to interupt the appleposse with java news).
>
> > > --
> > > You received this message because you are subscribed to the Google Groups
> > > "The Java Posse" group.
> > > To post to this group, send email to java...@googlegroups.com.
> > > To unsubscribe from this group, send email to
> > > javaposse+...@googlegroups.com<javaposse%2Bunsubscribe@googlegroups .com>
> > > .
> > > For more options, visit this group at
> > >http://groups.google.com/group/javaposse?hl=en.
>
> --
> You received this message because you are subscribed to the Google Groups "The Java Posse" group.
> To post to this group, send email to java...@googlegroups.com.
> To unsubscribe from this group, send email to javaposse+...@googlegroups.com.

Reinier Zwitserloot

unread,
Jun 1, 2010, 9:51:29 PM6/1/10
to The Java Posse
There's ongoing discussion about a keyword to mark a variable as heap-
hosted. Also, if you're using 1-dim arrays you're doing it wrong. Use
AtomicReference/AtomicInteger/AtomicDouble/etcetera instead.

Neal Gafter's definition of a closure is miles away from what we're
getting. Fortunately.

NB: The 'final limitation' exists because of confusion. For example,
what does this print:

Runnable[] r = new Runnable[3];
for (int i = 0; i < 3; i++) r[i] = #() {System.out.print(i);};
for (int i = 0; i < 3; i++) r[i].run();


Looks like it ought to print "123", right? Nope. It would print "333".
Which is confusing. Also, as closures can run anywhere it means local
variables may need synchronizing. So, should we now also allow
"volatile" on local variable declarations and abandon one of the few
last bastions of hope when trying to reason about rocket science
(read: multi-threading stuff), namely that local variables cannot be
shared with other threads, ever, and thus never need thinking about in
regards to locking?

Hence, I fully support at the very least the need to mark such shared
variables with some marker or other. One suggestion is to actually let
the compiler do its thing but emit a warning when it does, which can
be suppressed by adding an @Shared annotation to the local var.
Another one is that it's not legal java code unless you add either
"shared" (new context sensitive keyword) or "public" to the local var
declaration (existing keyword). A final one is that AtomicReference/
Integer/etc are good enough for any man. I like most of those.

Josh McDonald

unread,
Jun 2, 2010, 1:32:41 AM6/2/10
to java...@googlegroups.com
Sweet, thanks for that info :) I didn't know about MethodHandle, I'm assuming it's something like j.l.r.Method, but pre-bound to a specific "this"?

-Josh


On 1 June 2010 21:28, Reinier Zwitserloot <rein...@gmail.com> wrote:
A clarifying comment by Maurizio on lambda-dev claims that they are
currently implementing something that's similar to the straw man
presented by Mark Reinhold at Devoxx '09, with some of the tough
questions in it removed (such as using .() instead of plain parens to
'execute' a closure), so the widespread discussion on lambda-dev can
at least experiment better.

In otherwords, 'making the compiler-writer's job easy' is apparently
part of the plan, at least for now.

A standard function type in the JVM *already exists* in the jdk7
specs; it's called MethodHandle. There are already calls going out
amongst the alternative languages on the JVM crowd to start switching
to it. Also, partly motivated by the closures stuff, MethodHandle
objects will most likely gain a JVM-based 'asSam()' method which means
at least some of the structural typing that other languages offer can
be done 'natively' instead of working by using a lot of reflection
magic. So, Josh, Michael, time to lobby your friendly local
alternative language developer to get on the bandwagon :)





--
"Therefore, send not to know For whom the bell tolls. It tolls for thee."

Josh 'G-Funk' McDonald
  -  jo...@joshmcdonald.info

Kevin Wright

unread,
Jun 2, 2010, 2:16:31 AM6/2/10
to java...@googlegroups.com
On 2 June 2010 02:40, Reinier Zwitserloot <rein...@gmail.com> wrote:
Learning java closure syntax is more complicated than learning scala?
You've got to be kidding me.

I'm assuming that this is the sentence that prompted your outrage:

"Scala is, frankly, the lowest impact change for java developers willing to move to a better integrated functional syntax (at the cost of legacy functionality)"

The key phrase was "better integrated", it was a comparative, but to what?  To Java's proposed syntax of course!  So I was talking about the lowest impact of the alternatives to Java.  Presumably you don't consider Java to be an alternative to itself?

To avoid any further confusion, I'll rephrase it:

Having a functional syntax that is closely integrated into a language (ideally from the point of conception) is a desirable thing.  Unfortunately, this deep integration is not possible with Java due to backward-compatibility constraints.

For Java developers wanting a syntax that is more natural and effortless than this proposal, it would therefore seem wise to look beyond Java-the-Language.  In this broader space of alternate JVM languages the barrier to entry seems lowest for Scala, thanks to static typing and conscious efforts at making Java-Scala interop effortless.  Scala can be initially used as though it were no more than a tidied-up variant of Java, allowing developers to become productive again in a very short space of time.

 


You received this message because you are subscribed to the Google Groups "The Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.




--
Kevin Wright

Reinier Zwitserloot

unread,
Jun 2, 2010, 10:10:57 PM6/2/10
to The Java Posse
Not quite. MethodHandles aren't referring to a java library feature;
they are referring to a JVM feature. You can have an object-like
construct on the stack or on the heap, just like any other object or
primitive value, which represents a method invocation-to-be. This may
feel a little bit like a java.lang.reflect.Method object, but it's
different in a few ways:

1) It's a JVM-native concept. j.l.r.Method isn't; j.l.r.Method is a
fairly ordinary class where a bunch of its methods, including for
example 'invoke' are marked as 'native'. There's a difference; there
is no class file for MethodHandle at all, and its spec is much more
closely related to the core JVM C code itself, it's not just a sort of
add-on C file like j.l.r.Method's invoke.

2) The security checks on accessibility are done at the time the
method handle object is created. In other words, if code in A.class
creates a method handle to a private method 'foo' in A.class, and then
gives this method handle to B.class which then executes the method
handle, that works. If you were using j.l.r.Method, that wouldn't,
because j.l.r.Method does its security check on execute. You can of
course make j.l.r.Method work via .setAccessible(true) magic, but that
causes a call to the security manager. Note that the security model
isn't affected; if I have access to a method already I can of course
leak it to whomever I want, simply by wrapping a call to it into e.g.
a Runnable and passing that runnable around.

3) MethodHandles come in a few flavours and have certain flexibilities
(including the notion that MH's have a 'this' referent or not). For
example, there's a JVM-native-ish operation to curry them. (currying =
supplying some but not all parameters, effectively turning them into a
new method that takes less parameters. For example, turning add(int,
int) into add5(int) which always uses '5' as first argument. add5 is
like a new handle with a different signature). Currying without JVM
support is kinda annoying and somewhat pricey, as it would involve
creating a new class, running up permgen, causing a class parse hit,
etcetera.

4) MH's are designed primarily as a language-agnostic method handle
vehicle; they do NOT reflect any particular need for the java language
and are completely unrelated to the closures-for-java (a.k.a. project
lambda) effort, though most likely project lambda will gladly use the
MH feature. MH is being driven primarily by the alternative language
crowd.

5) In general, MHs are designed with speed, speed, speed, speed, and
low memory requirements in mind. Since java 1.4 j.l.r.Method isn't
exactly a sloth either, but MHs should be faster still, and take
considerably less permgen, which is a good thing.

On Jun 2, 7:32 am, Josh McDonald <j...@joshmcdonald.info> wrote:
> Sweet, thanks for that info :) I didn't know about MethodHandle, I'm
> assuming it's something like j.l.r.Method, but pre-bound to a specific
> "this"?
>
> -Josh
>
> On 1 June 2010 21:28, Reinier Zwitserloot <reini...@gmail.com> wrote:
>
>
>
>
>
> > A clarifying comment by Maurizio on lambda-dev claims that they are
> > currently implementing something that's similar to the straw man
> > presented by Mark Reinhold at Devoxx '09, with some of the tough
> > questions in it removed (such as using .() instead of plain parens to
> > 'execute' a closure), so the widespread discussion on lambda-dev can
> > at least experiment better.
>
> > In otherwords, 'making the compiler-writer's job easy' is apparently
> > part of the plan, at least for now.
>
> > A standard function type in the JVM *already exists* in the jdk7
> > specs; it's called MethodHandle. There are already calls going out
> > amongst the alternative languages on the JVM crowd to start switching
> > to it. Also, partly motivated by the closures stuff, MethodHandle
> > objects will most likely gain a JVM-based 'asSam()' method which means
> > at least some of the structural typing that other languages offer can
> > be done 'natively' instead of working by using a lot of reflection
> > magic. So, Josh, Michael, time to lobby your friendly local
> > alternative language developer to get on the bandwagon :)
>
> --
> "Therefore, send not to know For whom the bell tolls. It tolls for thee."
>
> Josh 'G-Funk' McDonald
>   -  j...@joshmcdonald.info

Josh McDonald

unread,
Jun 2, 2010, 10:15:57 PM6/2/10
to java...@googlegroups.com
Sweet, that kicks ass :)

--
You received this message because you are subscribed to the Google Groups "The Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.


--
"Therefore, send not to know For whom the bell tolls. It tolls for thee."

Josh 'G-Funk' McDonald
  -  jo...@joshmcdonald.info

opinali

unread,
Jun 4, 2010, 11:18:32 PM6/4/10
to The Java Posse
On 1 jun, 22:51, Reinier Zwitserloot <reini...@gmail.com> wrote:
> Neal Gafter's definition of a closure is miles away from what we're
> getting. Fortunately.

If you mean the requirement to capture unrestricted variables (not
just final ones), this is not "Neal's definition", this is everybody's
definition; it's _the_ formal definition of the closures concept
("function with free variables bound in its lexical environment").
Nobody ever discussed that for decades... until Java appeared with its
brain-damaged inner classes, and started teaching a whole generation
that closures are something complex, dangerous, confusing - unless we
protect stupid programmers with some limitations (which also
contradicts decades of experience with previous and current
languages).

A+
Osvaldo

Vince O'Sullivan

unread,
Jun 5, 2010, 2:05:55 AM6/5/10
to The Java Posse
On Jun 2, 2:51 am, Reinier Zwitserloot <reini...@gmail.com> wrote:
> NB: The 'final limitation' exists because of confusion. For example,
> what does this print:
>
> Runnable[] r = new Runnable[3];
> for (int i = 0; i < 3; i++) r[i] = #() {System.out.print(i);};
> for (int i = 0; i < 3; i++) r[i].run();
>
> Looks like it ought to print "123", right? Nope. It would print "333".
> Which is confusing.

OK, I'm confused. Explain, please.

B Smith-Mannschott

unread,
Jun 5, 2010, 4:57:56 AM6/5/10
to java...@googlegroups.com

Actually, I think Reiner's example is subtly misleading since each
iteration of the for loop conceptually gets a fresh variable 'i',
else using the final modifier would not be possible.

The example, using current Java:

Runnable[] r = new Runnable[3];

for (final int i = 0 ; i < 3; i++)
r[i] = new Runnable() {
public void run() { System.out.println(i); }
};


for (int i = 0; i < 3; i++)

r.run();

Prints 1 2 3

I suspect that if Java didn't require final i, the results would still
be the same, because the implementation would still be forced to copy
values into compiler-generated fields of the inner Runnable() class on
allocation. There's no way to store a reference to a variable in Java.
Having the compiler silently promote i to a mutable object on the heap
just so everyone can share a copy would be the only way to get the
behavior Reiner suggests and that just seems baroque.

***

There seems to be a lot of confusion in this discussion. There 's an
important distinction that we're glossing over, which causes us to
talk past each other. What *exactly* is the closure capturing? The
*variable* or the variable's *value*? This distinction is often not
clear to users of languages that pass everything by value, like Java.
A few examples:


# python
def demo():
x = 0
def foo():
x = 1
foo()
print x # prints 0

The inner function foo() captures read-only access to the outer variable x,
which leads to some oddities. x=1 actually creates a new 'x' local to
foo, hiding the outer x. reading from x in foo before assigning to it
will get us the outer x. Trying this x = x + 1 leads to a runtime
error because the x must necessarily be interpreted as local to foo in
that expression, but that means we can't read a value from it (the
second x in the expression) since it hasn't been bound (assigned to)
yet.

Python is capturing read-only access to the outer *variable* itself.
How can I tell it's not simply copying the value?

def example():
x = 0
def foo(): print x
foo(); x = 1; foo(); # output: 0 1


// java
void demo() {
final int x = 0;
new Runnable() {
public void run() {
x = 1; // COMPILE ERROR
}
}.run();
System.out.println(x);
}

Java protects us from the sort of confusion that Python can produce by
requiring outer variables be marked as 'final'. That way, there is no
expectation that they can be mutated from within the inner function
(the Runnable). Yes, the 'final' requirement is a little pedantic, but
at least
it's clear what the expected behavior is.

They could just as easily have defined that outer variables get copied
to compiler generated instance fields upon inner class creation (which
is what happens) and that left them mutable.

In any event, Java is capturing a *copies* of the *values* of outer
variables in its closure-like inner classes.


(* Oberon: sorry about the shouting *)
PROCEDURE Demo();
VAR x: INTEGER;
PROCEDURE Foo();
BEGIN
x := 1;
END Foo;
BEGIN
x := 0;
Foo;
Out.WriteInt(x); (* prints 1 *)
END Demo;

Foo has read/write access to the actual *variable* x, which is why
this example prints 1. The trade-off in this case is that the inner
procedure Foo can not outlive the call to Demo that created it. Oberon
doesn't have true Closures. The language enforces this by only
allowing top-level procedures to be assigned to variables are returned
from Functions.


;; clojure
(defn demo []
(let [x (atom 0)] ;; only references are mutable in clojure
(letfn [(foo [] (swap! x (constantly 1)))]
(foo)
(print @x)))) ;; prints 1

In Clojure the example almost doesn't make sense. Clojure variables
are all effectively final. i.e. They're not "variable", they're just
names for *values*. But it turns out, that some of these values can be
Clojure reference types, which allow mutability with defined
concurrency semantics.

Like Java, Clojure's closures capture the *values* of outer bindings
when they are created.


;; scheme
(define (demo)
(let ((x 0)
(foo (lambda () (set! x 1))))
(foo)
(print x))) ;; prints 1

Unlike Clojure, Scheme is permissive about mutability. Like Oberon,
foo captures the *variable* x. Unlike Oberon, this binding continues
to exist even after the call to demo completes. That is, foo has a
lifetime independent of demo.


As far as I am concerned, all of the presented languages (apart from
Oberon) can be said to have closures. Where they differ is in how
exactly they capture the surrounding environment. Do they capture
*values* or *variables*? Are they funky like Python?

// Ben

B Smith-Mannschott

unread,
Jun 5, 2010, 4:59:25 AM6/5/10
to java...@googlegroups.com
On Sat, Jun 5, 2010 at 10:57, B Smith-Mannschott <bsmit...@gmail.com> wrote:

> Runnable[] r = new Runnable[3];
> for (final int i = 0 ; i < 3; i++)
>  r[i] = new Runnable() {
>    public void run() { System.out.println(i); }
>  };
> for (int i = 0; i < 3; i++)
>  r.run();
>
> Prints 1 2 3

Prints 0 1 2

duh
//Ben

Reinier Zwitserloot

unread,
Jun 5, 2010, 6:15:10 AM6/5/10
to The Java Posse
Reply inline.

On Jun 5, 5:18 am, opinali <opin...@gmail.com> wrote:
> If you mean the requirement to capture unrestricted variables (not
> just final ones)

It wasn't.

Reinier Zwitserloot

unread,
Jun 5, 2010, 6:21:49 AM6/5/10
to The Java Posse
The closure captures the 'i' variable. While one might think there is
one such unique variable for every loop, this isn't true; there's only
one 'i' variable, and at the end of each iteration, this one variable
is incremented. Therefore, what's going on here, is that we have a
closure that will print 'the current value of whatever 'i' holds, 'i'
being the one counter variable that exists in the scope of the first
for loop in this code'.

The value of that 'i', at the time the closures are actually run, is
always 3. It has in fact rolled out of scope for the main method; the
only remaining code block that is still referencing it are those 3
closures, and they certainly don't modify 'i', they just print it.
Therefore the value would obviously have to be equal for each 'print'
result. The 'fixed' version looks like this:

Runnable[] r = new Runnable[3];
for (int i = 0; i < 3; i++) {
int temp = i;
r[i] = #() {System.out.println(temp);};
}
for (int i = 0; i < 3; i++) r[i].run();

That *WOULD* print "123" as one might at casual glance expect.
However, note that in this particular case, the current status quo
closure proposal would "just work" because temp is effectively final
(making it actually final does not cause a compiler error. hence, it
is effectively final). Even in the mildest forms of the various
alternative plans for how to handle capturing variables, making 'temp'
final would always be legal, and making it final here does not require
any rewriting (other than stuffing one 'final' keyword in the above
snippet, of course).


The BGGA-esque full capture proposal *STILL* supports the notion of at
least generating a warning when sharing mutable local variables, which
can be removed by adding a "@Shared" annotation on the variable
declaration, and it does NOT let you capture variables declared in the
'declaration' part of a standard for loop. For those who thought
Osvaldo was not completely off-base in his earlier rant because he
insinuated Neal Gafter's proposal includes unfettered access to
outside mutables - there you go. He's lying.

Reinier Zwitserloot

unread,
Jun 5, 2010, 6:42:57 AM6/5/10
to The Java Posse
Thanks for a very interesting post, Ben.

You did make one gigantic mistake though - your original java remarks
are completely wrong. Your snippet won't compile at all, and it'll
never print "012" no matter how you look at it.

You can't make the 'i' in:

for (int i = 0; i < 10; i++) { ... }

final. You could if you don't actually change i anywhere (INCLUDING
removing the 'i++'), but doing that would be completely pointless.

A few further remarks on your post inline:

On Jun 5, 10:57 am, B Smith-Mannschott <bsmith.o...@gmail.com> wrote:
> I suspect that if Java didn't require final i, the results would still
> be the same, because the implementation would still be forced to copy
> values into compiler-generated fields of the inner Runnable() class on
> allocation.

Nope, that 'baroque' suggestion you had that the compiler has to
silently promote i to a mutable object on heap is ACTUALLY WHAT WOULD
HAVE TO HAPPEN. This is exactly why 'final' is required, because then
the 'I'll just copy it' approach is indistinguishable from actually
capturing the variable itself. *ALL* closure proposals for java that
include modifyable locals (be it 'silently', be it with a warning, be
it only if you add 'public' or 'shared' or some other keyword) by way
of declaring that variable on the heap, effectively replacing 'shared
int x = 10;' with 'final MutableInteger x = new MutableInteger(10);',
if that helps clarify the situation.

Note that your other examples of other languages all work the same way
too. The compilers involved detect the sharing situation and
completely change how the variable is created and accessed, at all
levels (both inside and outside the closures). Exactly how else do you
think this is going to work (other than the oberon case, which really
does truly capture a stack-hosted variable)? Note that JVM rocket
scientists have already explained at length (and using mostly rocket
science) that actually adding support to access, let alone mutate,
local variables from inside closures is completely infeasible and
would be way slower than any emulation via heap objects injected by
the compiler.

NB: I'm sure Ben gets this, but we sort of glossed over an important
point here: That local variables in java are basically hosted on the
stack. Each thread has its own stack, and everything a method puts on
a stack just disappears immediately when the method exits. A stack
cannot continue to operate until that happens, in fact (you simply
CANNOT return control back to your caller until everything you did to
the stack is undone). Closures, which can be moved to another thread
and can outlive the method they were declared in, rather obviously
cannot share its host method's stack space, and as a result, it cannot
access any variables its containing method has on the stack either.


> What *exactly* is the closure capturing? The
> *variable* or the variable's *value*?

The variable itself, not the value. Period. Always. In any language,
or they're abusing the term "closure" even more than java already
does. Java, to be precise, has never strayed from this definition
either, and is not going to. Right now it doesn't really matter
because java's reaction to capturing a non-final variable is always:
Make it final first. And for final variables, the distinction between
capturing the variable and its value is moot.

> A few examples:
>
> [snip python's WTF way of handling variable capture in python closures]

Oh, hey, thanks for reminding me and sharing this one with the still
interested reader. You're quite right about python's strange behaviour
here. Osvaldo (and any other hot-heads who think this stuff is 'easy'
in other languages) - take note.

> In any event, Java is capturing a *copies* of the *values* of outer
> variables in its closure-like inner classes.

That's an implementation detail that is attempting (successfully) to
emulate the semantically correct notion of accessing the original
variable itself. The emulation works because captured variables are
always final (in java, at any rate), and with final variables, copying
them or accessing the original is indistinguishable.

> The trade-off in this case is that the inner
> procedure Foo can not outlive the call to Demo that created it.

Ah, but, this is where the discussion gets really interesting! There
are a few at this point mostly abandoned closure proposals and add-ons
to proposals out there which make a distinction between 'safe' and
'unsafe' closures. Primarily these terms refer to the notion that the
closure, if run at all, will only be run when the method that declared
them is still around on the same stack. The oberon limitation is
REQUIRED if you want to "long break", "long continue" or "long return"
out of a method. In most proposals (including BGGA's safe/unsafe add-
on) this concept is intended to be a compile-time consideration only,
with the class verifier not worried in the slightest, because if this
invariant is broken the JVM won't crash, you'll simply get a
TransferError exception.

However, if you do move this concept into the JVM itself, verified by
the verifier, you could in fact have your notion of "true" variable
capture.

To be perfectly clear, this is no where near project lambda right now.
Nevertheless it's interesting. And on a personal note I think we
should definitely be going there, mostly because you can do so much
fun stuff when you have that 'origin is still on the stack' guarantee,
such as long returns/breaks/continues, but also a form of exception
transparency: When the runtime stack and the lexical stack are
guaranteed to be synced up, you can catch exceptions thrown INSIDE
your closures on the OUTSIDE of them, just like you can e.g. catch
exceptions thrown inside the body of a for loop outside a for loop.

B Smith-Mannschott

unread,
Jun 5, 2010, 7:06:32 AM6/5/10
to java...@googlegroups.com
On Sat, Jun 5, 2010 at 12:42, Reinier Zwitserloot <rein...@gmail.com> wrote:
> Thanks for a very interesting post, Ben.
>
> You did make one gigantic mistake though - your original java remarks
> are completely wrong. Your snippet won't compile at all, and it'll
> never print "012" no matter how you look at it.
>
> You can't make the 'i' in:
>
> for (int i = 0; i < 10; i++) { ... }
>
> final. You could if you don't actually change i anywhere (INCLUDING
> removing the 'i++'), but doing that would be completely pointless.

You're quite correct, I've gotten to used to

for (final Object a: array_of_Object), where this works. I would have
had to introduce a (final) temporary variable at the top of the loop
to make my example work.

for (int i = 0; i < 10; i++) {

final int temp = i;
... new Runnable() { ... temp ... };

// ben

B Smith-Mannschott

unread,
Jun 5, 2010, 9:37:18 AM6/5/10
to java...@googlegroups.com
On Sat, Jun 5, 2010 at 12:42, Reinier Zwitserloot <rein...@gmail.com> wrote:
> On Jun 5, 10:57 am, B Smith-Mannschott <bsmith.o...@gmail.com> wrote:
>> I suspect that if Java didn't require final i, the results would still
>> be the same, because the implementation would still be forced to copy
>> values into compiler-generated fields of the inner Runnable() class on
>> allocation.

[ ... snip ... ]

>> What *exactly* is the closure capturing? The
>> *variable* or the variable's *value*?
>
> The variable itself, not the value. Period. Always. In any language,
> or they're abusing the term "closure" even more than java already
> does. Java, to be precise, has never strayed from this definition
> either, and is not going to. Right now it doesn't really matter
> because java's reaction to capturing a non-final variable is always:
> Make it final first. And for final variables, the distinction between
> capturing the variable and its value is moot.

Good analysis. I guess where we differ is that I'm willing to accept
closures which copy only the values as sufficient. There are two
reasons for this:

(1) I'm getting away from mutable state in my programming anyway, and
as you point out the two approaches are indistinguishable when
variables are immutable. So, I'm not losing much by having closures
that copy values rather than capture variables.

(2) In my experience having closures capture mutable variables is
mostly useful for simulating stateful objects (e.g. doing OOP in
Scheme), but in Java we don't need to simulate objects and classes
using closures.

p.s. For those who haven't read it, there's a cute little koan about
the equivalence of objects and closures (in the full
variable-capturing sense) at the end of the post linked below:

http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html

Reinier Zwitserloot

unread,
Jun 5, 2010, 3:48:51 PM6/5/10
to The Java Posse
I dunno. I think the python case pretty clearly shows that letting
'variable capture' mean: 'value only', which the python version is
more or less close to (though, technically, as you showed with your
example where the closure captures an outer in read-only mode by
mutating the outer and showing the effect in the closure) - is going
to be hopelessly confusing. Folks expect something that looks like the
same variable (as in: Declared only once, used in two places) to be
_the same variable_, and not secretly 2 variables that are one-way
synced up, once, at the _definition_ of the closure.

Regardless of what makes the most sense, absolutely no proposals for
project lambda in regards to how to handle capturing variables
involves capturing copies (unless said variable is final, in which
case as I mentioned before, the difference is simply irrelevant).

On Jun 5, 3:37 pm, B Smith-Mannschott <bsmith.o...@gmail.com> wrote:

opinali

unread,
Jun 7, 2010, 9:26:46 AM6/7/10
to The Java Posse
Ok, that was implied by the context of that email (quoted content
'heap and avoid the annoying "final limitation". This does not match
Neal Gafter's definition of a closure').

Anyway, the debate now drifted to whether capturing a COPY of
variables (or only capture their value) is sufficient. This patently
absurd. Even if we have a new paradigm that favors avoidance of
mutable variables (and I certainly subscribe to this), let's not play
revisionism and redefine a classic, fundamental CS concept that was
cast in stone forty years ago and which exact meaning was crystal-
clear and NEVER debated... before some Java advocates appeared with
nonsensical, bastardized closures. This kind of attitudes - both
avoiding a no-brainer feature like true closures, and doing a half-
assed attempt but claiming that it is a closure - makes Java the
laughing stock of serious programming language designers. Just create
a new term that is not "closure", and assume publicly that Java does
not have closures and will never have closures. It's not like we are
butchering live kitten or something. Well, almost.

A+
Osvaldo

Reinier Zwitserloot

unread,
Jun 7, 2010, 1:56:23 PM6/7/10
to The Java Posse
One person in this entire thread is hammering the "copy" notion
somewhat heavily, though he did back that up with some real-life
examples in other languages, and most importantly is referring to an
implementation detail. Stop being so paranoid.

The exact meaning of the word "closure" is of course hotly debated,
not properly defined, and especially in regards to working with some
obvious and logical constraints that must be adhered to if closures
are to be added to java, really a rather nebulous concept. I don't
really care how much you keep beating this drum of "My meaning is the
only right one and the rest of y'all are engaging in something I find
patently absurd" - it's you who is holding absurd notions here. How
to add closures to java is not a no-brainer. The meaning of the term
"closure" is like most other tech terms bastardized. Welcome to the
world. Our languages are living, mutating entities. I suggest you
learn to deal with it instead of go off on a rant every time.

Russel Winder

unread,
Jun 7, 2010, 2:32:10 PM6/7/10
to java...@googlegroups.com
On Mon, 2010-06-07 at 10:56 -0700, Reinier Zwitserloot wrote:
[ . . . ]

> The exact meaning of the word "closure" is of course hotly debated,
> not properly defined, and especially in regards to working with some
> obvious and logical constraints that must be adhered to if closures
> are to be added to java, really a rather nebulous concept. I don't
> really care how much you keep beating this drum of "My meaning is the
> only right one and the rest of y'all are engaging in something I find
> patently absurd" - it's you who is holding absurd notions here. How
> to add closures to java is not a no-brainer. The meaning of the term
> "closure" is like most other tech terms bastardized. Welcome to the
> world. Our languages are living, mutating entities. I suggest you
> learn to deal with it instead of go off on a rant every time.

The definition may be hotly debated in some circles (almost exclusively
Groovy and Python ones), but in most places the definition is well
understood and indeed well defined. From some dictionary or other:

. . . a closure is a data structure that holds an expression and
an environment of variable bindings in which that expression is
to be evaluated.

see also Simon L Peyton Jones, "The Implementation of Functional
Languages", Prentice-Hall, p.378, where different words are used but the
meaning is the same.

Language is indeed a living and mutating entity, but it much better not
to run headlong into "Humpty Dumpty Syndrome"

`When I use a word,' Humpty Dumpty said in rather a scornful
tone, `it means just what I choose it to mean -- neither more
nor less.'

In fact the meaning of a word is a social construct. Jargon is slightly
different in that there needs to be a common definition in order for the
term to be at all useful. There is currently a definition of closure
which works very well for almost all of the world of programming and
computing (except Groovy), let's stick to it.

--
Russel.
=============================================================================
Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel...@ekiga.net
41 Buckmaster Road m: +44 7770 465 077 xmpp: rus...@russel.org.uk
London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder

signature.asc

Reinier Zwitserloot

unread,
Jun 7, 2010, 5:41:03 PM6/7/10
to The Java Posse
The meaning of the word "closure" is perfectly well understood within
the java community. Syntax for portable code blocks. No more no less.
I've also caught the dictionary thumpers in outright fabrications
before, for example the notion that the final variables only
restriction somehow means project lambda's proposal isn't a closure
proposal. That's just wrong. *ALL* variables are closed over, but
accessing some variables may cause a compiler error. The compiler
still knows which variable you're talking about. Saying this means
it's not the dictionary definition of closure is akin to suggesting
the inability to extend final classes somehow means java isn't OO.
> Dr Russel Winder      t: +44 20 7585 2200   voip: sip:russel.win...@ekiga.net
> 41 Buckmaster Road    m: +44 7770 465 077   xmpp: rus...@russel.org.uk
> London SW11 1EN, UK   w:www.russel.org.uk skype: russel_winder
>
>  signature.asc
> < 1KViewDownload

Casper Bang

unread,
Jun 10, 2010, 12:44:09 PM6/10/10
to The Java Posse
Once again, Stephen Colebourne to the rescue?

http://mail.openjdk.java.net/pipermail/lambda-dev/2010-June/001544.html

I like it, reads much easier than the Strawman proposal (people
already have a hard enough time with bounds and co/contra-variance
without tossing the throws keyword in there).

Reinier Zwitserloot

unread,
Jun 10, 2010, 8:21:55 PM6/10/10
to The Java Posse
Casper, lone throws is a tiny, tiny part of closures.

gafter

unread,
Jun 13, 2010, 2:52:35 PM6/13/10
to The Java Posse
Colebourne essentially proposes to deprecate checked exceptions. It
will be a cool day in heck before that happens.

Current discussion on the lambda mailing list suggests it may be
possible to do without the throws keyword in a type parameter.

Viktor Klang

unread,
Jun 13, 2010, 3:30:11 PM6/13/10
to java...@googlegroups.com
On Sun, Jun 13, 2010 at 8:52 PM, gafter <neal....@gmail.com> wrote:
On Jun 10, 9:44 am, Casper Bang <casper.b...@gmail.com> wrote:
> Once again, Stephen Colebourne to the rescue?
>
> http://mail.openjdk.java.net/pipermail/lambda-dev/2010-June/001544.html
>
> I like it, reads much easier than the Strawman proposal (people
> already have a hard enough time with bounds and co/contra-variance
> without tossing the throws keyword in there).

Colebourne essentially proposes to deprecate checked exceptions.  It
will be a cool day in heck before that happens.

'Tis ok, us in Scalaland are already free. :)
 

Current discussion on the lambda mailing list suggests it may be
possible to do without the throws keyword in a type parameter.
--
You received this message because you are subscribed to the Google Groups "The Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.




--
Viktor Klang
| "A complex system that works is invariably
| found to have evolved from a simple system
| that worked." - John Gall

Akka - the Actor Kernel: Akkasource.org
Twttr: twitter.com/viktorklang

Kevin Wright

unread,
Jun 13, 2010, 4:29:35 PM6/13/10
to java...@googlegroups.com
On 13 June 2010 20:30, Viktor Klang <viktor...@gmail.com> wrote:


On Sun, Jun 13, 2010 at 8:52 PM, gafter <neal....@gmail.com> wrote:
On Jun 10, 9:44 am, Casper Bang <casper.b...@gmail.com> wrote:
> Once again, Stephen Colebourne to the rescue?
>
> http://mail.openjdk.java.net/pipermail/lambda-dev/2010-June/001544.html
>
> I like it, reads much easier than the Strawman proposal (people
> already have a hard enough time with bounds and co/contra-variance
> without tossing the throws keyword in there).

Colebourne essentially proposes to deprecate checked exceptions.  It
will be a cool day in heck before that happens.

'Tis ok, us in Scalaland are already free. :)
 

You forgot to mention that we also already have closures, and have had them for quite some time now...
 

Current discussion on the lambda mailing list suggests it may be
possible to do without the throws keyword in a type parameter.

--
You received this message because you are subscribed to the Google Groups "The Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.




--
Viktor Klang
| "A complex system that works is invariably
| found to have evolved from a simple system
| that worked." - John Gall

Akka - the Actor Kernel: Akkasource.org
Twttr: twitter.com/viktorklang

--
You received this message because you are subscribed to the Google Groups "The Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.



--

Casper Bang

unread,
Jun 13, 2010, 4:39:14 PM6/13/10
to The Java Posse
> You forgot to mention that we also already have closures, and have had them
> for quite some time now...

Of course so does C#, probably the most comparable language to Java.

Kevin Wright

unread,
Jun 13, 2010, 4:48:14 PM6/13/10
to java...@googlegroups.com
For a given value of "comparable"... does it have a .net posse, eh?

 

--
You received this message because you are subscribed to the Google Groups "The Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.

Casper Bang

unread,
Jun 13, 2010, 5:33:31 PM6/13/10
to The Java Posse
> For a given value of "comparable"... does it have a .net posse, eh?

Well it has .NET rocks among others. The core difference seems to be
in cross-pollination - for some reason a large part of the Java crowd
likes to pretend C# doesn't exist, which I always thought was a
dangerously closed mindset if we want to push the art forward. C# had
type-safe method handles in 1.0 (2000), which was evolved into
anonymous methods with 2.0 (2005) while finally lambda expressions
were introduced with 3.5 (2007). So it predates Scala quite a bit and
I still have my doubt whether Scala will ever move from the elite into
mainstream. But that's another story, better not hijack the thread...
Reply all
Reply to author
Forward
0 new messages