Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #20867 > unrolled thread

Re: Why is that in JDK8: value used in lambda expression shuld be effectively final?

Started byjeti789@web.de
First post2013-01-02 07:08 -0800
Last post2013-01-05 12:58 +0000
Articles 5 on this page of 25 — 7 participants

Back to article view | Back to comp.lang.java.programmer

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? jeti789@web.de - 2013-01-02 07:08 -0800
    Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? jeti789@web.de - 2013-01-02 07:52 -0800
    Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Steven Simpson <ss@domain.invalid> - 2013-01-02 17:33 +0000
      Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Saxo <jeti789@web.de> - 2013-01-02 11:31 -0800
        Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Lew <lewbloch@gmail.com> - 2013-01-02 12:52 -0800
          Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Arved Sandstrom <asandstrom2@eastlink.ca> - 2013-01-02 20:58 -0400
            Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Lew <lewbloch@gmail.com> - 2013-01-02 17:40 -0800
              Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Arved Sandstrom <asandstrom2@eastlink.ca> - 2013-01-03 20:43 -0400
          Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Saxo <jeti789@web.de> - 2013-01-02 23:44 -0800
            Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Patricia Shanahan <pats@acm.org> - 2013-01-03 07:57 -0800
              Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Lew <lewbloch@gmail.com> - 2013-01-03 13:22 -0800
                Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Patricia Shanahan <pats@acm.org> - 2013-01-03 16:14 -0800
        Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Steven Simpson <ss@domain.invalid> - 2013-01-02 21:46 +0000
          Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Lew <lewbloch@gmail.com> - 2013-01-02 17:35 -0800
          Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Saxo <jeti789@web.de> - 2013-01-03 02:13 -0800
            Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Saxo <jeti789@web.de> - 2013-01-03 06:45 -0800
              Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Steven Simpson <ss@domain.invalid> - 2013-01-04 21:32 +0000
                Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Peter Duniho <NpOeStPeAdM@NnOwSlPiAnMk.com> - 2013-01-04 14:38 -0800
                  Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Steven Simpson <ss@domain.invalid> - 2013-01-04 23:45 +0000
                    Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Peter Duniho <NpOeStPeAdM@NnOwSlPiAnMk.com> - 2013-01-04 17:24 -0800
                      Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Steven Simpson <ss@domain.invalid> - 2013-01-05 13:20 +0000
                Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Saxo <jeti789@web.de> - 2013-01-05 01:50 -0800
                  Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Steven Simpson <ss@domain.invalid> - 2013-01-05 11:21 +0000
                    Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Saxo <jeti789@web.de> - 2013-01-05 04:27 -0800
                      Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Steven Simpson <ss@domain.invalid> - 2013-01-05 12:58 +0000

Page 2 of 2 — ← Prev page 1 [2]


#20984

FromSteven Simpson <ss@domain.invalid>
Date2013-01-05 13:20 +0000
Message-ID<atllr9-v74.ln1@s.simpson148.btinternet.com>
In reply to#20964
On 05/01/13 01:24, Peter Duniho wrote:
> On Fri, 04 Jan 2013 23:45:54 +0000, Steven Simpson wrote:
>> [...]
>> Do these examples fall into just a couple of categories, in terms of the
>> guarantees that the user of a function object makes to the provider
>> about how it will be invoked?:
>>
>>   1. The object will be invoked on the same thread that provided it (e.g.
>>      in an event-driven environment)
>>   2. (1) + the object will not be invoked once the call that provided it
>>      has completed (e.g. in control abstraction)
>>
>> ...or are there more, especially ones which make fewer or alternative
>> guarantees?
> Honestly, I'm not aware of a lambda/closure taxonomy that uses those
> categories at all.  If such exists, I am ignorant of it.

That's because I'm making them up!  :-D

The goal I'm trying to reason my way towards is that, since Java is 
supposed to provide a degree of safety (and so mutable local capture and 
other features are currently missing from its 'closures'), there ought 
to be a way to signal to the compiler cases where it is safe to enable 
those features.  Rather than the provider of the function object 
choosing when it is safe (e.g. by annotating shared variables with 
@Shared, or manually boxing them in 1-element arrays), the user of the 
object should choose by annotating the parameter that conveys the 
object, because that user is in a position to make guarantees about the use.


> First and foremost is that the "user of a function object" often has no
> knowledge that a closure is being used at all.  It knows it's received a
> function object of some sort (e.g. a delegate instance in C#/.NET), but the
> origin of that object could be varied.

That's why I used the term 'function object'.


> A given API may or may not make promises regarding usage of the function
> object, but these promises likely have little to do with the declaration
> and implementation of the function object.

Whatever form the function object was originally expressed as, the one 
who invokes it is in a position to make guarantees about how it is 
invoked, and I'm suggesting that these promises could influence the 
options available for expressing the function object.


> Beyond that, wrt point #1: function objects, even those made from closures
> with captured variables, may be safely invoked even in a multi-threaded
> environment, so long as the code is written correctly.  For example,
> enforcing volatile or fully-synchronized access to shared variables
> (whether due to capturing or otherwise).

I would expect a good proportion of these cases to end up requiring 
certain objects to be created explicitly anyway, simply to have 
something to synchronize on, in which case, Java's lambdas would be 
adequate because the variables would explicitly be not local.

But I don't know, hence I'm asking for examples.


> Wrt point #2: because variable capturing involves effectively "lifting" the
> variable out of the declaring method's local context, invoking the function
> object after the declaring method has completed is not a concern at all.

(That wasn't the concern particularly, though I think there have been 
notions that MLC would be achieved by means other than boxing, and such 
means would depend on the local's lifetime.  I don't know enough about 
this to elaborate.)

The idea behind #2 is that there is a class of closure use cases which 
are really demanding control abstraction.  If the function-object user 
makes sufficient promises about how it is invoked, the compiler could 
permit a control-abstraction syntax as an alternative to a lambda, in 
which the code can do anything that a local block could do, including 
throwing, returning, breaking, continuing.

If one can show that practically all cases with a /prima facie/ demand 
for additional features from Java lambdas actually fall into categories 
#1 or #2, it guides us in developing additional closure features for 
Java that satisfy the conflicting demands of safety versus expressiveness.

An argument about category #1 could run something like this...  One camp 
demands to be able to write:

   int sum = 0;
   list.forEach((v) -> { sum += v; });

Another camp says, "ouch, don't like that!" because forEach might 
execute the lambda in parallel.  You should therefore get an error or 
warning about shared access to 'sum'.

The first camp says, "okay, we'll take responsibility for 'sum' by 
declaring that we know it's shared," and either boxes the variable 
manually, or proposes an annotation to silence the warning or permit the 
code:

   @Shared
   int sum = 0;
   list.forEach((v) -> { sum += v; });

The problem is that this depends on whether the author has understood 
the (informal) guarantees that might be provided by forEach: "This 
method invokes its argument multiple times in serial."

Instead of the author of the code above deciding when it's safe to use 
MLC, a serial contract for forEach should formally express the 
guarantee, (say) by annotating its parameter:

   void forEach(@Serial Block action);

The compiler then turns on MLC for any lambda assigned to 'action', 
without having to use @Shared or explicit boxing.  Of course, the 
implementation has to make the corresponding guarantee to meet the 
method's contract.

Alongside forEach could be parallelForEach:

   void parallelForEach(Block action);

The lack of annotation means that its implementation does not have to 
make the guarantee.

The provider of a lambda now has a choice between a potentially parallel 
implementation, which won't allow MLC, and a guaranteed serial one, 
which will.

The no-MLC camp is happy, because they can provide parallelForEach 
exploiting parallelism, and know that the user won't inadvertently mess 
about with locals unsafely.  The MLC camp is happy, because they can use 
forEach to mutate their locals safely.

Some obvious holes include:

  * A method accepting a @Serial Block could fail to make the serial
    guarantee, and the compiler would not be able to check it.  However,
    I don't think that's much worse than the compiler not being able to
    check that (say) a Comparator implementation isn't returning random
    values.
  * I'm using annotations as if they are some sort of type qualifier,
    which I doubt is a valid way to regard them. Not sure.



-- 
ss at comp dot lancs dot ac dot uk

[toc] | [prev] | [next] | [standalone]


#20972

FromSaxo <jeti789@web.de>
Date2013-01-05 01:50 -0800
Message-ID<6f020a38-4566-4739-8ec7-a85d02a68d86@googlegroups.com>
In reply to#20955
Am Freitag, 4. Januar 2013 22:32:38 UTC+1 schrieb Steven Simpson:
> On 03/01/13 14:45, Saxo wrote:
> 
> 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. 

Groovy:

def list = [1, 2, 3]
def sum = 0
list.each { sum += it }
println(sum)

Kotlin:

val list = arrayListOf(1, 2, 3)
var sum = 0;
list.forEach { i -> sum += i }
println(sum)

Scala:

val list = List(1, 2, 3)          
var sum = 0        	  
list.foreach(sum += _)
println(sum)

Works in all these languages that support closures (and I guess in any other language that supports closures as well), but the same does not work with JDK8 lambdas.

Reality can be tough... There is always the workaround of defining a single element array final:

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

I wrote in my blog:

The lambda specification (JSR 335) also says so explicitly: "For both lambda bodies and inner classes, local variables in the enclosing context can only be referenced if they are final or effectively final. A variable is effectively final if it is never assigned to after its initialization.".

And I provided the link to JSR 335: http://cr.openjdk.java.net/~dlsmith/jsr335-0.6.1/B.html

I took some effort in my blog to describe the matter and provided the links to the respective resources on the JDK8 lambda homepage :-).

OTOH, JDK8 lambdas are still enormously useful. No doubt about that. An imense amount of pre-JDK8 boilerplate code can be thrown out of myriads of systems, frameworks and applications. It's a big step ahead. Nevertheless, it can be said that JDK8 lambdas don't go all the way to be called true closures. Apparently, JDK8 lambdas can be assigned to a Runnable. Maybe this was a deliberate choice to stay backwards compatible. 

-- Oliver

[toc] | [prev] | [next] | [standalone]


#20976

FromSteven Simpson <ss@domain.invalid>
Date2013-01-05 11:21 +0000
Message-ID<jvelr9-ck2.ln1@s.simpson148.btinternet.com>
In reply to#20972
On 05/01/13 09:50, Saxo wrote:
> Am Freitag, 4. Januar 2013 22:32:38 UTC+1 schrieb Steven Simpson:
>> On 03/01/13 14:45, Saxo wrote:
>>
>> 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.
> Groovy:
>
> def list = [1, 2, 3]
> def sum = 0
> list.each { sum += it }
> println(sum)
>
> Kotlin:
>
> val list = arrayListOf(1, 2, 3)
> var sum = 0;
> list.forEach { i -> sum += i }
> println(sum)
>
> Scala:
>
> val list = List(1, 2, 3)
> var sum = 0        	
> list.foreach(sum += _)
> println(sum)

Sorry, but aren't these the same example that you originally gave, just 
in different languages?  I'm looking for different examples, perhaps 
expressed in a Java-like language with the features you were hoping for.


> Apparently, JDK8 lambdas can be assigned to a Runnable.

...if they take no arguments, returning nothing, and throw no checked 
exceptions.  Java lambdas don't have their own special function types, 
and have to be associated with a SAM type as soon as they are 
expressed.  Type inference is expected to make this implicit in most cases.

-- 
ss at comp dot lancs dot ac dot uk

[toc] | [prev] | [next] | [standalone]


#20977

FromSaxo <jeti789@web.de>
Date2013-01-05 04:27 -0800
Message-ID<0b4ba911-8f69-44a2-839c-ec3d2b002e8e@googlegroups.com>
In reply to#20976
Am Samstag, 5. Januar 2013 12:21:55 UTC+1 schrieb Steven Simpson:

> Sorry, but aren't these the same example that you originally gave, just 
> in different languages?  

No, because it works in all these languages what with JDK8 lambdas would only work if sum were declared final.

Remember this one:

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. 

Maybe I had a point there with those 95%, because discussions like this one you will have with 95 java developers out of 100...

-- Oliver

[toc] | [prev] | [next] | [standalone]


#20980

FromSteven Simpson <ss@domain.invalid>
Date2013-01-05 12:58 +0000
Message-ID<9lklr9-tk3.ln1@s.simpson148.btinternet.com>
In reply to#20977
On 05/01/13 12:27, Saxo wrote:
> Am Samstag, 5. Januar 2013 12:21:55 UTC+1 schrieb Steven Simpson:
>> Sorry, but aren't these the same example that you originally gave, just
>> in different languages?
> No, because it works in all these languages what with JDK8 lambdas would only work if sum were declared final.

I understand that they work in those languages, and that they don't work 
when directly translated into Java, because Java 'closures' lack a 
feature provided by the other languages.

To put it another way, if you regard your original example as written in 
a fictional language similar to Java - one that supports MLC, and so 
doesn't throw an error back at you - it would be equivalent to each of 
the Groovy/Kotlin/Scala examples you listed.

-- 
ss at comp dot lancs dot ac dot uk

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.java.programmer


csiph-web