Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8013650

Clarify constant variables and constant fields

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 8
    • 7
    • specification
    • None
    • Verified

      There are four "constant" concepts in the JLS which intertwine static and final:

      1. A "constant expression" has always been defined by JLS 15.28 as involving final variables (static or non-static).

      2. A "constant variable" was introduced by JLS3 4.12.4 as a final variable (static or non-static) that is assigned to a constant expression.

      3. A "constant field" has always been alluded to by JLS 8.3.2.1 (and the last paragraph of 9.3.1) as a _static_ final field initialized with a constant expression. (This expression necessarily contains only the names of other constant fields, since the name of a non-static final field is illegal in the static context where a constant field is declared.) The ConstantValue attribute in JVMS 4.7.2 serves to represent the value of a "constant field" at runtime. Together, the Java language and JVM provide a very strong guarantee for a constant field, namely that no program can observe the field having the default value for its type; the value of the constant expression is assigned to the field early in the initialization process.

      4. A "constant" has always been the informal name in JLS 9 for the (implicitly) static final field of an interface, despite the fact that it does not need to be initialized with a constant expression. It does not help that JLS 9.3.1 discusses the treatment of interface fields that _are_ initialized with constant expressions, and calls such fields "constants" too.

      Note that a constant variable has a declared type which is primitive or String, but the type of a static final field is not mentioned in 8.3.2.1 or 9.3.1, nor in the initialization algorithm of 12.4.2 or JVMS 5.5. It might appear from 12.4.2 that a static final field whose declared type is, say, Object, and which is assigned to a constant expression will be initialized early. In fact, the Java language does not intend to guarantee early initialization in this case, because determining if the right hand side of an assignment expression is "really" a constant expression is undecidable. (It is possible to observe the default value - 'null' in this case - by declaring an earlier static final field which is assigned to the result of calling a method that "peeks" at the Object field; see example 8.3.2.3-1.) This is why 13.1 only requires resolution of references to constant variables, rather than any final variable initialized with a constant expression. And so, because 13.1 surreptitiously mandates a ConstantValue attribute (the true guarantor of early initialization) only if the declared type is primitive or String, it is appropriate to tighten the language's model of initialization in 12.4.2: "Then, initialize the static fields of C which are constant variables." It is _not_ necessary to tighten JVMS 5.5: at the JVM level, a field whose field_info structure has a ConstantValue attribute should enjoy early initialization, regardless of the field's type.

      For clarity, the JLS should speak solely of "constant expression" and "constant variable". As a nod to the past, the word "constant" without "expression" or "variable" afterwards should appear only in the JLS 9 introduction. "constant value" should be avoided wholesale. Thus:

      - 8.3.2.1 should say: "At run time, static fields that are constant variables (§4.12.4) are initialized first (§12.4.2). This also applies to such fields in interfaces (§9.3.1). These fields will never be observed to have their default initial values (§4.12.5), even by devious programs."

      - 9.3.1 should say: "At run time, interface fields that are constant variables (§4.12.4) are initialized first (§12.4.2). This also applies to static fields that are constant variables in classes. These fields will never be observed to have their default initial values (§4.12.5), even by devious programs." 6.1 should say "A field declared in an interface type", rather than "A constant field declared in an interface type".

      - 13.1 item 3 should continue to speak of "References to fields that are constant variables" - not necessarily static - but should replace "constant value that is denoted" with "the value V produced by evaluating the constant variable's initializer". Item 3 continues by alluding to class initialization so should limit its scope carefully: "If such a field is static, then no reference to the field should be present in the code of any binary file, including the class or interface which declared it. Such a field must always appear to have been initialized (§12.4.2); the default initial value for the field (if different than V) must never be observed." Finally, item 3 can give the non-static case: "If such a field is non-static, then the binary file for the class which declares the field (it will be a class since an interface has only static fields) should have code to set the field's value to V during instance creation (12.5)."

      - 13.4.9 is obtuse in starting off by talking about final but then using static in both examples. 13.4.9-1 does not need static - Super.s can be non-static and it's still a binary-incompatible change to turn it from non-final to final.

      - 14.21 says "A change to the value of a flag is, therefore, not binary compatible with pre-existing binaries" - this is directly contradicted by 13.4.9 ("changing its value will not break compatibility with pre-existing binaries"). 14.21 makes the distressingly common error of saying "binary compatibility" without realizing the specific linkage-oriented meaning of the phrase. A change to the value of a flag is simply ignored by pre-existing binaries; at most there is a behavioral incompatibility here, but that's outside the scope of the JLS.

      - 15.28 and throughout: In "compile-time constant expression", the "compile-time" is redundant.

      - JVMS 4.7.2 serves two purposes: 1) for a static final field assigned to a constant expression, the attribute stores the value of the constant expression for use during class or interface initialization and during compilation; and 2) for a non-static final field assigned to a constant expression, the attribute stores the value for use during compilation. So, 4.7.2 should say "A ConstantValue attribute represents the value of a constant expression to be assigned to a field." Then 4.7.2 should proceed to distinguish a field_info representing a static field (assigned during class or interface initialization) from a non-static field (silently ignored by the JVM [but not by Java compilers]).

            abuckley Alex Buckley
            abuckley Alex Buckley
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: