javaconstructorfieldfinal

Initializing a final field in a constructor using Class.this.field = value gives an error whereas using this.field = value doesn't


class A {
    final int a;
    A () {
        this.a = 1; // No error
    }
}

whereas the below code

class A {
    final int a;
    A () {
        A.this.a = 1; // Error: java: cannot assign a value to final variable a
    }
}

Using this.a to assign a value to a final field works fine. But using A.this.a to assign a value to the final field gives an error "java: cannot assign a value to final variable a". Not sure why?

I understand that there are no reason in this case to explicitly use A.this.a instead of this.a. Just wanted to understand the reason.


Solution

  • From this bug report, JVM architect John Rose mentioned that the definite assignment (DA) of blank final fields (e.g. a in your code) are only tracked by the simple name a, and this.a. Other more complex expressions like A.this.a are not considered when determining whether the field is definitely assigned.

    In the present case, the rather arbitrary choice was made (by Bill Joy and me, IIRC, back in Java 1.1 times) to perform static checking of blank final non-static field initialization by tracking uses of either the bare field name "x" or the simply qualified field name "this.x" but by no other, more complex expression. In other words, this "bug" is an intentional feature in the design of the JLS.

    He explains the reasoning further:

    we wanted to allow only the bare field name "x" to participate in the static analysis of DU/DA; this would be the simplest formulation of the DU/DA rules. We added exactly "this.x" as an alternative in order to respect the reasonable practice of giving constructor parameters and fields the same names (a practice confirmed by Java records).

    But keeping this names tracked by DU/DA as simple as possible is important, because they are already complex enough that the compiler has to train the user (with error messages like the one this bug reports) how to stay within the bounds of DU/DA correctness. Arbitrarily adding a more complex grammar of names that DU/DA works on adds to the complexity of an already hard-to-predict analysis. It makes code harder to read and mentally validate, in particular.

    In short, this is an arbitrary choice. They kept the DA rules simple.