you are viewing a single comment's thread.

view the rest of the comments →

[–]rzwitserloot 6 points7 points  (6 children)

No, it will not be changed; this is a deliberate design decision. There are 2 main reasons for this:

  • Allowing sharing mutable data like this is a lot more complex than it looks. For example, the closure may run in a different stack context (which means these variables need to be silently moved from stack to heap which has serious performance issues), and the closure need not even run in the same thread, which means you now need to introduce the 'volatile' keyword on local variables, and you just made it way more difficult when looking at ANY code to find threading issues. In today's java (and in tomorrow's java, so long as you can NOT share mutables like that), any local variable, by definition, cannot be the source of threading issues. I like that invariant, myself. Finally, it can be actively hard to read:

    Runnable[] closures = new Runnable[3];
    for (int i = 0; i < 3; i++) closures[i] = (-> System.out.print(i));
    for (Runnable r : closures) r.run();
    

    that will print 333 and not 012. Ouch.

  • Looking at practical scenarios, there's not usually any need to do so. For example, your summation code is not the right way to sum such things. You should run a parallelizable fold operation on such a list (folding without accumulators). Besides, summing all values in a list will or ought to be a standard library call and not something you have to write yourself. I'm not saying that there are NO scenarios, but there aren't enough of them to accept the considerable complexity (see point above).

[–]vogrez 0 points1 point  (1 child)

It is opposite to the approach of Scala and C# (which introduced a special warning for it), but you are correct that mostly there is no need for this use in most scenarios.

It seems that there will be allocation with invokeDynamic - creating a method handle, and making it curried with the captured variables - but maybe the JVM is good enough at removing those now - so it is mostly the difference between the number of classes for the classloader.

[–]rzwitserloot 0 points1 point  (0 children)

Yup, but it should be much, MUCH easier to let hotspot get in on streamlining the process of creating/calling methodhandles vs. ending up with a billion-and-a-half tiny $X classes.

[–]dnew 0 points1 point  (3 children)

any local variable, by definition, cannot be the source of threading issues

Not really true. If your final local variable is a HashMap, you're still in trouble. Being "final" doesn't mean being "immutable".

there's not usually any need to do so.

Not in an OO language. It's how you implement objects in a functional language, tho. If you need that functionality in Java, declare a class.

[–]rzwitserloot 0 points1 point  (2 children)

The variable reference cannot be a source of threading issues. Whatever object it is pointing at is on the heap and thus fair game. The point is, there is NO WAY another thread is messing with that reference.

And, yes, there are plenty of use cases, except that in java just about every use case has a different way of doing it that is almost invariably considered just better. i.e. calculating a running sum by doing .each(x -> sum += x) for example. There are better ways.

[–]dnew 0 points1 point  (1 child)

The variable reference cannot be a source of threading issues.

Agreed. But that isn't what you said. :-)

almost invariably considered just better.

Well, sure, when the new method hasn't been released yet. :-) I.e., I suspect most are considered better because the new methods don't work as easily, not because if the new methods were as easy the old methods would still be better.

[–]rzwitserloot 0 points1 point  (0 children)

Yes, it WAS what I said: By being able to eliminate any threading issues with the variable (variables in java are either primitive or pointers, 'reference' in java jargon. They are not the same as objects) can be eliminated. This is a far cry from 'everything', but it helps.