JDK-8025762 : 8.3.3: Clarify that a field cannot be referenced in its own initializer
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 1.2.0,5.0,7,8
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2013-10-01
  • Updated: 2018-08-03
  • Resolved: 2016-10-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description
The rules in 8.3.2.3 (8.3.3 in JLS 8) are designed to prevent circularity in the initialization of fields.  This is accomplished by requiring that most references to a field in a field initializer (or initializer block) must happen _after_ the declaration of the field.  But, strangely, I can't find an explicit rule prohibiting the simplest circularity of all: a field that refers to itself.

class Foo { int i = i+1; } // error in javac

JLS 1 8.3.2.2 said "A compile-time error occurs if an initialization expression for an instance variable contains a use by a simple name of that instance variable or of another instance variable whose declaration occurs to its right (that is, textually later) in the same class." And, "int k = k+1;" was exemplified as an error "because the initialization of k refers to k itself."

JLS 2 rewrote these sections and no longer explicitly prohibited a field from being used in its own initializer.

---

Suggested text:

Use of instance variables whose declarations ***contain or*** appear textually after the use is sometimes restricted, even though these instance variables are in scope. Specifically, it is a compile-time error if all of the following conditions hold:

��� The declaration of an instance variable in a class or interface C ***either contains or*** appears textually after a use of the instance variable;

��� The use is a simple name in either an instance variable initializer of C or an instance initializer of C;

��� The use is not on the left hand side of an assignment;

��� C is the innermost class or interface enclosing the use.

[May also want to update some informal descriptions of this rule appearing elsewhere in 8.3.2.]
Comments
8.3.2 should state that: ----- References from variable initializers to fields that may not yet be initialized are subject to additional restrictions, as specified in 8.3.3 and Chapter 16. ----- I propose the following text as the entirety of 8.3.3: ----- References to a field are sometimes restricted, even through the field is in scope. For a reference by simple name to a class variable f declared in class or interface C, it is a compile-time error if: - The reference appears either in a class variable initializer of C or in a static initializer of C; and - The reference appears either in the initializer of f's own declarator or at a point to the left of f's declarator; and - The reference is not on the left hand side of an assignment expression; and - The innermost class or interface enclosing the reference is C. For a reference by simple name to an instance variable f declared in class C, it is a compile-time error if: - The reference appears either in an instance variable initializer of C or an instance initializer of C; and - The reference appears either in the initializer of f's own declarator or at a point to the left of f's declarator; and - The reference is not on the left hand side of an assignment expression; and - The innermost class enclosing the reference is C. ----- - Notice use of "declarator" rather than "declaration" throughout. This precision helps when a FieldDeclaration contains declarators for multiple fields. - Notice "to the left of", per 3.5. (Tweak clauses in 8.3.2, 8.6, and 8.7 in sympathy.) - I like splitting the class variable and instance variable cases, in sympathy with 8.3.2. (JLS3's 8.3.3 combined the cases, and I thought that needlessly terse given how 8.3.2 spelled them out separately.) I propose to title 8.3.3 as "Restrictions on Field References in Initializers". The legacy title "Forward References During Field Initialization" omits self-references -- in my view, "int i = i+1;" does not have a forward reference in the sense of "declaration appears textually after use" because the declaration starts prior to the use. Also, 8.3.2 "Field Initialization" is solely about variable initializers in declarators, but 8.3.3 sneaks in the {static,instance} initializer case where there is assignment, of course, but no variable initializers in the sense of the FieldDeclaration nonterminal.
17-10-2016

Looks good. Two minor comments: - "class or interface C" can just be "class C" in the instance field case���interfaces don't have instance fields - I might try to use the word "initialization" in the title or first sentence to convey a sense of the scope of this restriction, although I realize something like "during initialization" is informal and imprecise. Not quite sure what I'd say... Also, this may be useful from the previous iteration, which I suggested adding to 8.3.2: ***References from field initializers to fields that may not yet be initialized are subject to additional restrictions, as specified in 8.3.3 and Chapter 16.***
17-10-2016

The rule that allows self-references in inner classes is: "Specifically, it is a compile-time error if all of the following are true: ... C is the innermost class or interface enclosing the use." So the spec fix will not affect the treatment of references from inner classes.
04-10-2016

In 7, we have the same thing with inner classes as we do in 8 with lambdas; a field that accesses "itself" in the course of initializing an inner class instance is really capturing 'this'.
12-11-2013

Brian: let's discuss that as a possible feature enhancement, but this bug is about the JLS 7 text, which needs cleaning up.
12-11-2013

I don't think that a lambda that references a field of the current class is referencing the field. For instance fields, such lambdas capture 'this', not individual fields. By the time the lambda executes, the field will be initialized.
07-11-2013