JDK-8027941 : javac fails with "self-reference in initializer" when referencing the static field from lambda
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Priority: P2
  • Status: Resolved
  • Resolution: Not an Issue
  • Submitted: 2013-11-06
  • Updated: 2013-11-12
  • Resolved: 2013-11-12
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
See attached test case.

import java.util.function.Function;

public class LambdaSelfRef {

    // COMPILATION FAILURE
    public static Function<Object, Object> op1 = e -> op1.apply(e);

    // COMPILES OK
    public static Function<Object, Object> op2 = e -> LambdaSelfRef.op2.apply(e);

    // COMPILES OK
    public static Function<Object, Object> op3 = new Function<Object, Object>() {
            public Object apply(Object o) {
                return op3.apply(o);
            }
        };

    // COMPILES OK
    public static Function<Object, Object> op4 = new Function<Object, Object>() {
            public Object apply(Object o) {
                return LambdaSelfRef.op4.apply(o);
            }
        };
}

The weird thing is that accessing the static field via class works perfectly. Seems to be constrained to lambdas, anonymous classes permit the behavior we are after.
Comments
Linking to JDK-8025762, which points out that the "appears textually after" phrase needs to clarify that it applies to self-references as well as forward references.
12-11-2013

Not a bug. Nor is it a lambda-specific behavior. See JLS 8.3.2.3: "The declaration of a member needs to appear textually before it is used only if the member is a static field of a class or interface C and all of the following conditions hold:" "- The usage occurs in a static variable initializer of C or in a static initializer of C." "- The usage is not on the left hand side of an assignment." "- The usage is via a simple name." "- C is the innermost class or interface enclosing the usage." These conditions apply for op1, but not for op2, op3, or op4. It would possible to _add_ a feature that would treat lambda bodies specially, like bodies of anonymous classes (or, more generally, allow a lambda to refer to itself if it is a variable initializer), but this has not been done. (FWIW, a straightforward tweak of 8.3.2.3 would not be entirely safe, just like the 4th bullet is not currently entirely safe: "Function f = (Function) ((Function) e -> f.apply(e)).apply(null);".)
12-11-2013

This raises the specification questions, reassigning to specification and Dan.
07-11-2013

This is a consequence of JDK-8024809, there are comments in the bug entry by Dan Smith which include the related spec sections. So it's OK that the first example doesn't compile and it's OK that the second does. This is the workaround that was left available.
07-11-2013