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.

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(

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.

* 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