Why is that in JDK8: value used in lambda expression shuld beeffectively final?

J

jeti789

I'm currently plaing with JDK8 and using lambda-8-b69-windows-i586-17_dec_2012. I wonder why this does not compile:

List<Integer> ints = new ArrayList<>();
ints.add(1);
ints.add(2);
ints.add(3);

int sum = 0;
ints.forEach(i -> {sum += i;});

The compiler error is "value used in lambda expression shuld be effectively final"

However, this here compiles:

int sumArray[] = new int[] { 0 };
ints.forEach(i -> {sumArray[0] += i;});

I'm a bit confused now. Does this mean that JDK8 closures are no true closures or is this a bug in my IDE (IDEA 12)?

Thanks, Oliver
 
S

Steven Simpson

I'm currently plaing with JDK8 and using lambda-8-b69-windows-i586-17_dec_2012. I wonder why this does not compile:

List<Integer> ints = new ArrayList<>();
ints.add(1);
ints.add(2);
ints.add(3);

int sum = 0;
ints.forEach(i -> {sum += i;});

The compiler error is "value used in lambda expression shuld be effectively final"

It's the same reason why inner classes can't mutate local variables in
the enclosing scope. The method that accepts the lambda or inner class
instance cannot formally make any guarantee not to invoke the supplied
code in a non-serial way.

forEach could informally specify that it will execute its argument only
on its calling thread, and not after it returns, but the compiler could
not detect that guarantee and allow 'sum' to be modified.

(I'm using 'formal' to indicate something that can be detected by the
compiler.)

However, this here compiles:

int sumArray[] = new int[] { 0 };
ints.forEach(i -> {sumArray[0] += i;});

Ultimately, the compiler can't stop anyone from shooting themselves in
the foot. You can still access an instance variable unsafely via a
lambda, for example.

Stopping the protection at the level of local variables could seem a bit
arbitrary, but it is still useful, since you expect the use of local
variables to be intrinsically thread-safe (and they remain so under this
level of protection), and trying to provide more comprehensive
protection would be increasingly difficult.

I'm a bit confused now. Does this mean that JDK8 closures are no true closures or is this a bug in my IDE (IDEA 12)?

For some definition of closures (one including mutable local capture),
JDK8 lambdas are not closures (hence, they are not called closures).
AIUI, the main goal of lambdas was to reduce verbosity/overhead of
anonymous classes used with algorithms that better exploit parallelism.
These do not typically require or work well with shared variables, and
supporting mutable locals efficiently would require considerable extra
effort for something substantially beyond the main goal.

I'm sure you can get a more authoritative explanation by checking the
lambda mailing-list archives:

<http://mail.openjdk.java.net/pipermail/lambda-dev/>

I suggest looking for terms such as 'mutable local capture', and
'effectively final'.
 
S

Stefan Ram

int sum = 0;
ints.forEach(i -> {sum += i;});
The compiler error is "value used in lambda expression shuld be effectively final"

I have no knowledge about or experience with the Java 1.8
lambdas, but my idea (made up by me right now) is:

You are passing »i -> {sum += i;}« to »ints«, which (»ints«)
is an object on the heap. This object »ints« may still hold
a reference to »i -> {sum += i;}«, when the method that
contained »int sum = 0;« already has expired. »sum« seems
to be a stack variable. So »ints« then might still hold
»i -> {sum += i;}«, but where is the variable »sum« then?
However, this here compiles:
int sumArray[] = new int[] { 0 };
ints.forEach(i -> {sumArray[0] += i;});

This array lives on the heap and might outlive its function.

The compiler error message sounds strange, because a »value«
cannot be final, only a variable can be final. A value is
something like »4« or »8«. Values never change, even without
»final«.
 
J

jeti789

Hi Steven,

thanks for your elaborte answer.
For some definition of closures (one including mutable local capture),
JDK8 lambdas are not closures (hence, they are not called closures).

I see, I didn't know. I wished Sun/Oracle had made this more clear ...
AIUI, the main goal of lambdas was to reduce verbosity/overhead of
anonymous classes used with algorithms that better exploit >parallelism.

Well, JDK8 lambdas how they must be called then do at least reduce the amount of boilerplate code ...

Anyhow, this news does really put a smile on my face. Guess it's really time to look for another JVM-based language like Groovy or Scala ;-).

Regards, Oliver
 
J

jeti789

Anyhow, this news does really put a smile on my face.

.... does NOT put a smile on my face, of course. Guess this will give Groovy2.0 more momentum.
 
S

Steven Simpson

Anyhow, this news does [not] really put a smile on my face. Guess it's really time to look for another JVM-based language like Groovy or Scala ;-).

For your particular case:

List<Integer> ints = ...;
int sum = 0;
ints.forEach(i -> { sum += i; });

....the recommended way is to use something like:

int sum = ints.reduce(0, (x, y) -> x + y);

....which is more parallel-friendly. Of course, if you don't care about
the parallelism, it's simply:

int sum = 0;
for (int i : ints)
sum += i;

I'm sure you're just using this example to explore what's available, and
I think it would be a mistake to discard Java based on it. So is there
a more sophisticated case you were hoping would improve with lambdas?
 
S

Saxo

Hm... Maybe it was done that way for backwards compatibility. JDK8 lambdas are like less verbose annonymous classes and nothing more ...
 
S

Saxo

I'm sure you're just using this example to explore what's available,

Yes, exactly. This little code snippet to calcualate a sum is a very simplebut canonical case of a closure that has a free variable:

"When a function refers to a variable defined outside it, it's called a free variable. A function that refers to a free lexical variable is called a closure.". Paul Graham, ANSI Common Lisp, Prentice Hall, 1996, p.107.

So free variables aren't possible with JDK8 lambdas. For people used to closures, this is surely surprising. Well, this does not render JDK8 lambdas useless. On the contrary, an imense amount of boilerplate code that is necessary without them can be removed with them. Once the JDK8 gets released this will be an eye-opener to about 95% of all Java developers (the ratio of Java developers not understanding closures ...).
I think it would be a mistake to discard Java based on it.

If I could I would have done that a long time ago. But not going with a M$ language was a deliberate decision and on the JVM nothing will rival Java (only be a complement like Groovy, or scratch on it like Scala or Kotlin).
int sum = ints.reduce(0, (x, y) -> x + y);

Nice, but it does not compile with me. I use IDEA 12 and the lambda-8-b69-windows-i586-17_dec_2012 JDK. Seems like reduce does not exist in Iterator or Collection!?

-- Oliver
 
L

Lew

Saxo said:
So free variables aren't possible with JDK8 lambdas. For people used to closures, this is surely
surprising. Well, this does not render JDK8 lambdas useless. On the contrary, an imense amount of
boilerplate code that is necessary without them can be removed with them. Once the JDK8 gets
released this will be an eye-opener to
about 95% of all Java developers (the ratio of Java developers not understanding closures ...).

The ratio of Java developers who do not understand closures is probably pretty close to the
ratio of Java developers who do not understand Java.

Aside from that your comment is unsupportable. Or do you have evidence?

....

I thought not.
 
S

Steven Simpson

Nice, but it does not compile with me. I use IDEA 12 and the lambda-8-b69-windows-i586-17_dec_2012 JDK. Seems like reduce does not exist in Iterator or Collection!?

I figured, if forEach is on Collection, reduce likely would be too. I
did try to have a look for it in source, but wasn't sure if I had the
right branch. I also didn't find the javadoc on-line. Based on the
source, try:

ints.stream().reduce(0, (x, y) -> x + y)
 
A

Arved Sandstrom

The ratio of Java developers who do not understand closures is probably pretty close to the
ratio of Java developers who do not understand Java.
[ SNIP ]

I don't get that statement at all. A significant percentage of Java
programmers don't use any other languages in a big way, including those
that do have closures. And since Java itself doesn't have them (*), I
just don't see why a programmer who understand Java really well can't
also *not* know about closures.

AHS

* I'll wager that a lot of Java programmers - the ones with their hands
full still doing their production work in JDK 1.6 and 1.7, say, don't
have time to play with experimental features.
 
L

Lew

Steven said:
I figured, if forEach is on Collection, reduce likely would be too. I

'forEach' is not on Collection. It's on Collection's parent type.
did try to have a look for it in source, but wasn't sure if I had the
right branch. I also didn't find the javadoc on-line. Based on the
source, try:

Javadoc for Java 8 is on line:
http://download.java.net/jdk8/docs/api/index.html

Not hard to find, but it doesn't contain the information you wanted.

ints.stream().reduce(0, (x, y) -> x + y)

http://datumedge.blogspot.com/2012/06/java-8-lambdas.html
gives a brief overview.
 
L

Lew

Arved said:
The ratio of Java developers who do not understand closures is probably pretty close to the
ratio of Java developers who do not understand Java.

[ SNIP ]
I don't get that statement at all. A significant percentage of Java

You mean you don't agree with it. Apparently you do get it.
programmers don't use any other languages in a big way, including those

How significant? What percentage? Aren't these the same ones I said don't understand
Java either?

How do you know they aren't?
that do have closures. And since Java itself doesn't have them (*), I
just don't see why a programmer who understand Java really well can't
also *not* know about closures.

Can, certainly. But the statement was statistical, not possibilistic.

Where does "95%" come from? Where does "significant percentage" come from?

My point is that there are no data for these assertions. Likewise, I have no data, but
unless you do you have nothing with which to refute my assertion.

Plus there's the aforementioned matter of agreeing on definitions.
* I'll wager that a lot of Java programmers - the ones with their hands

How much is "a lot"? Does it approach 95%?
full still doing their production work in JDK 1.6 and 1.7, say, don't
have time to play with experimental features.

I have my hands full doing production work in JDK 1.6 and 1.7. Yet I do play with
experimental features, and even read about them beyond that.

Doesn't everyone? Don't you?

Anyone who doesn't, doesn't understand Java.
 
S

Saxo

Aside from that your comment is unsupportable. Or do you have evidence?

What I mean is that almost every Java developer I met during the last 10 years didn't know what I meant when I said it's a pitty that Java does not have closures. I can't remember anyone who asked anything else in return than"and what are closures?". Having worked some of these years as a consultant I did see places. Almost nobody are those famous 95%. Funny that people get that annoyed. For the older guys that have worked with some other language than Java before the difference f.ex. between Smalltalk developers and Java developers is striking in terms of intellectual reflection, general interest, etc. Probably a good place to be nowadays is the people from the Scala camp.

-- Oliver
 
S

Stefan Ram

Saxo said:
What I mean is that almost every Java developer I met during
the last 10 years didn't know what I meant when I said it's a
pitty that Java does not have closures.

Clojure already exists, and everyone who wants to program
the LISP style is free to choose LISP or Clojure.

Using LISP style in Java is not necessarily good Java style!

For a Java programmer, good knowledge of Java is already
sufficient. He does not need to know terminology of other
languages!

»Almost every English speaker I met didn't know what I
meant, when I said it's a pitty that English does not
have an ablative.«

What in LISP is expressed by creating a new closure, in Java
can be expressed by creating a new instance of a class.

( SETQ ADDER( LAMBDA( N )( LAMBDA( X )( + X N ))))

becomes

public class Adder
{ private final int n;
public Adder( final int n ){ this.n = n; }
public int add( final int x ){ return x + this.n; }}
 
L

Lew

On this newsgroup there've been spirited discussions on this topic for years.

In my experience over the last ten years lots and lots of Java programmers, most
of the ones with whom I've spoken, knew what closures were if they were reasonably
competent Java programmers.

But I don't claim statistical significance for my non-random idiosyncratic sample.
You should not either.

The fact that my experience is the opposite of yours should be evidence for that.

For the record, I argued vehemently against the addition of closures to Java.

I tend to agree with Stefan here.
Wrong.

...
I would distinguish different levels of programming skill. If one is
going to be making decisions such as choosing the language for a
project, it is important to understand the capabilities and supported
programming styles for a wide variety of languages.

Similarly, anyone working in programming language design and
standardization should understand the possibilities that have been
demonstrated by other languages.

For someone who is just programming in one language, it is enough to
know that language well.

Wrong.

It is not enough.

Because people who learn only Java tend not to even program Java well.

That I've seen. I don't know if that has statistical significance.

But based on my experience and much reading and the advice of mentors,
I will state unequivocally that knowledge of only Java makes a terrible computer
programmer.

Simply terrible.

Any real programmer would have learned at *least* one other language, usually
prior to learning Java, and would understand things like computable pointers.

Anyone who calls themselves a programmer and is unwilling to learn a second programming
language is an ass and needs to switch to serving fries to fast-food customers.
 
A

Arved Sandstrom

Arved said:
Lew said:
Saxo wrote:
So free variables aren't possible with JDK8 lambdas. For people used to closures, this is surely
surprising. Well, this does not render JDK8 lambdas useless. On the contrary, an imense amount of
boilerplate code that is necessary without them can be removed with them. Once the JDK8 gets
released this will be an eye-opener to
about 95% of all Java developers (the ratio of Java developers not understanding closures ...).
The ratio of Java developers who do not understand closures is probably pretty close to the
ratio of Java developers who do not understand Java.

[ SNIP ]
I don't get that statement at all. A significant percentage of Java

You mean you don't agree with it. Apparently you do get it.
programmers don't use any other languages in a big way, including those

How significant? What percentage? Aren't these the same ones I said don't understand
Java either?

How do you know they aren't?
that do have closures. And since Java itself doesn't have them (*), I
just don't see why a programmer who understand Java really well can't
also *not* know about closures.

Can, certainly. But the statement was statistical, not possibilistic.

Where does "95%" come from? Where does "significant percentage" come from?

My point is that there are no data for these assertions. Likewise, I have no data, but
unless you do you have nothing with which to refute my assertion.

Plus there's the aforementioned matter of agreeing on definitions.
* I'll wager that a lot of Java programmers - the ones with their hands

How much is "a lot"? Does it approach 95%?
full still doing their production work in JDK 1.6 and 1.7, say, don't
have time to play with experimental features.

I have my hands full doing production work in JDK 1.6 and 1.7. Yet I do play with
experimental features, and even read about them beyond that.

Doesn't everyone? Don't you?

Anyone who doesn't, doesn't understand Java.
Well, we can agree on one thing - absent hard numbers - which I'm not
sure exist - none of us have more than anecdotes.

I'll say this - I've worked closely with hundreds of programmers over my
career. Not just Java, obviously, everything under the sun. I've
interviewed many dozens of developers. I've seen a humungous amount of
code written by other people. I read professionally voraciously.

These same statements are probably applicable to you and a bunch of
other people in this NG too.

_My_ takeaway from all that is that most professional working
programmers are M-F 9-5. They don't actually spend time at home coding
or doing professional development (with the exception of training or
reading books that help them with the immediate technologies that they
need *now*). They don't have more than an above-average grasp of
anything, they aren't even that interested in the field.

So no, I don't believe for a second that more than 5 or 10 percent of
coders play with experimental features or learn languages that they may
never use on the job...let alone teach themselves CS underpinnings of
what they do.

But this is all anecdotal. You may have all your career worked with
young hard-chargers who absolutely live to code. You'd see things
differently.

As for *me*, the new _language_ features in Java 7 don't exactly take
more than a few hours to read about and trial out in a simple test
program. I spent rather more time investigating the new APIs in 7, so I
know what's there and can plan to use it if appropriate.

As for what is coming out in 8, I could not care less. I really could
not. I'm not using 8 yet, and none of my Java work (which these days is
a small bit of what I do) will even be on the Java 8 platform for years.
So why waste my time? I'd rather hone up on Scala, Clojure, latest C#,
and F#...to name a few.

AHS
 
S

Steven Simpson


I'm still interested in seeing an example that you would normally write
with free variables, demonstrating that lambdas are inadequate for the
things you'd like to do. The example you provided of summing integers
has two alternatives, so it only serves to show that free variables are
not possible, not that free variables are necessary.

Can you contrive something more sophisticated, as an exercise?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top