Effectively final effective?
Artur Biesiadowski
abies at adres.pl
Thu Feb 25 12:38:38 PST 2010
Reinier Zwitserloot wrote:
> And yet that's what you are proposing: To avoid a simple, obvious, and
> direct error message ("this variable is implicitly final because it is
> accessed from a closure; if you'd like to mutate it, use
> AtomicReference"), you've set up a situation where you implicitly
> create a copy of a variable, and changing the one does not reflect
> into the other. Horrible, _horrible_ idea.
I'm suggesting making it effectively final in the scope of
lambda/anonymous class, just not outside of it. As far as bugs or
understanding the concept is concerned, I do not see any fundamental
difference between
int i;
for (i =0; i < 10; i++ ) {
list.add(new Integer(i));
}
print(list);
and
int i;
for (i =0; i < 10; i++ ) {
list.add(new Object() { public String toString() { return
Integer.toString(i);}});
}
print(list);
In both cases, value of the variable is captured at the moment it
appears in source code. Same way as you will not expect to see ten of
'10' in first case, you won't expect to see ten '10' in second case.
Still, you are arguing that while first case is obvious and will not
cause bugs, second case HAS to be written
int i;
for (i =0; i < 10; i++ ) {
final int j = i;
list.add(new Object() { public String toString() { return
Integer.toString(j);}});
}
print(list);
(with final possibly being removed if I understand your position
correctly). Can you imagine explaining to newcomers in java (after final
is removed) that they have to do int j =i; in the loop to pass the
variable inside, because if they would NOT reassign it to different
name, they would make a mistake of expecting 10x10 as the output?
Example with loop is one of the main cases where I'm really angry about
current rules (as I use final modifier for the most of normal, non-loop
variables anyway) - of course, in real life it is bit more complicated :)
I think that having similar rules for method arguments and variables
passed into lambdas/anonymous classes is not bad thing (after all, in
both cases you are doing a method/function call, just code is inlined in
case of lambda/anonymous class as opposed to normal method call).
Given something like @Shared would be accepted, all attempts to modify
variable from inside closed scope would result in warning (make it
shared or use in read mode only), but would not impose limits on the
outside. Going further this route, to achieve symmetry between the
inlined methods and normal methods, I could even imagine this evolving
into by-reference passing for java. You would declare method
void swap(@Shared int a, @Shared int b);
and then you could pass variables declared as @Shared to swap, knowing
that they will be mutated inside your scope. If passed into non-shared
receiver, current value would be used. I would probably disallow
automagical 'sharing' of normal variable if it is used as argument to
method expecting @Shared - it should be compilation error (as @Shared
will be most probably just a syntax sugar around AtomicXYZ or WrappedXYZ).
Anyway, I'm not advocating particular solution for @Shared here - just
showing that there is a certain symmetry between method calls and lambda
instantiations and I don't think it is unreasonable to expect closing
over CURRENT value of variable being natural.
Regards,
Artur Biesiadowski
More information about the lambda-dev
mailing list