Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #20867 > unrolled thread
| Started by | jeti789@web.de |
|---|---|
| First post | 2013-01-02 07:08 -0800 |
| Last post | 2013-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.
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]
| From | Steven Simpson <ss@domain.invalid> |
|---|---|
| Date | 2013-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]
| From | Saxo <jeti789@web.de> |
|---|---|
| Date | 2013-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]
| From | Steven Simpson <ss@domain.invalid> |
|---|---|
| Date | 2013-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]
| From | Saxo <jeti789@web.de> |
|---|---|
| Date | 2013-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]
| From | Steven Simpson <ss@domain.invalid> |
|---|---|
| Date | 2013-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