Bug in javac and eclipse ??
Remi Forax
forax at univ-mlv.fr
Wed Jan 22 00:28:10 PST 2014
On 01/22/2014 04:36 AM, Zhong Yu wrote:
> On Tue, Jan 21, 2014 at 5:14 PM, Dan Smith <daniel.smith at oracle.com> wrote:
>> The relevant spec (unchanged by Lambda) is 8.3.3. The error is as specified.
>>
>> This has been on the radar for a few months, with emails about it popping up periodically. See, e.g, the "Reader mail bag, 2nd edition" email:
>>
>>> 3 Dec 2013, Markus Keller <markus_keller at ch.ibm.com>, "Self-reference to field from lambda expression in initializer"
>>> I've had quite a few discussions about this, and concluded that it is best not to do anything until we flesh out a potential "recursive lambda expression" feature in the future. (In 8, local variables initialized with lambdas have a similar inability to directly refer to themselves.)
>> Adding to that conclusion a bit:
>>
>> - It is sometimes safe to refer to field inside a lambda in its initializer body, but not always (e.g., what if you immediately invoke a lambda in the initializer?)
> Prior to lambda, if a field initializer references the field itself,
> it's highly likely that it is a programming mistake, for example, `int
> y = y+1;`. It makes sense to forbid it because in all likelihood
> that'll help the programmer.
>
> But it is not true if the field is referenced inside a lambda body. It
> is very un-likely that it is a programming mistake. It's most likely
> what the programmer intends it to be.
yes,
BTW, what I wanted to write is a destructured(*) visitor which is as you
said is a legit code.
public static final Visitor<Integer> EVAL_VISITOR =
new Visitor<Integer>()
.when(Value.class, Value::getValue)
.when(BinOp.class, expr -> expr.getOp().applyAsInt(
EVAL_VISITOR.visit(expr.getLeft()),
EVAL_VISITOR.visit(expr.getRight())));
but with the current rule, either you have to qualify the reference to
the visitor or
you can call a mustache to the rescue :)
public static final Visitor<Integer> EVAL_VISITOR =
new Visitor<Integer>() {{ // <- mustache
this.when(Value.class, Value::getValue)
.when(BinOp.class, expr -> expr.getOp().applyAsInt(
visit(expr.getLeft()), visit(expr.getRight())));
}};
sadly mustache solution generates an anonymous class.
Rémi
* I call it a destructured visitor just for the sake of give it a name.
it's a practical answer to the expression problem described by Philip
Wadler [1] (it doesn't solve it because there is a hidden cast), the
code of the Visitor is left as an exercise for the reader.
[1] http://homepages.inf.ed.ac.uk/wadler/papers/expression/expression.txt
>
>> - Were we to come up with a perfect rule, the rules for when it's safe to refer to a field would be the same as the rules for when it's safe to refer to a local variable. (Noting, however, that the requirements of the language are different: it is never tolerable to refer to a local variable before initialization, while early access to fields is sometimes permitted.)
>>
>> - The approach we took in JSR 335 in general was to claim that recursive lambdas were probably not all that useful, and wait for evidence to the contrary.
> I've encountered it in my real-world code. Basically the lambda is
> registered as an one-off listener to some event; when the event
> occurs, the lambda may need to register itself again. This example is
> by no means contrived, and I'll bet $20 that we'll hear a lot of
> complains why this cannot be done. And the workaround (prefixing with
> "this." or "TheClass.") will only seem to be mysterious.
>
> Zhong Yu
>
>> An argument for more convenient recursive access in field initializers is probably also an argument for support for recursive access from local variable initializers.
>>
>> - In any case, you can always use qualified access ('System.out.println(ReferenceProblem.constant)'), for which 8.3.3 does not apply.
>>
>> —Dan
>>
>> On Jan 21, 2014, at 3:23 PM, Remi Forax <forax at univ-mlv.fr> wrote:
>>
>>> (CC lambda-dev)
>>> This code do not compile neither with Eclipse nor with javac, but I think that both are wrong.
>>>
>>> public class ReferenceProblem {
>>> static class A {
>>> public A(Runnable r) { }
>>> }
>>>
>>> static final A constant = new A(() -> {
>>> System.out.println(constant);
>>> });
>>> }
>>>
>>> javac talks about 'self reference' but there is no self reference here, a lambda is a delayed computation.
>>> 15.27.2 only concern local variables, so I don't think this code should be rejected.
>>>
>>> cheers,
>>> Rémi
>>>
More information about the lambda-spec-experts
mailing list