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

Clarify enclosing instances of nested classes

XMLWordPrintable

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

      Consider this simple program:

      class Foo {
        class Bar {} /* Inner member class */

        void m() { new Bar(); }
      }

      Given "new Bar()", JLS 15.9.2 determines that there is an immediately enclosing instance of the new Bar object, namely the current Foo object. Similarly, if "new Foo().new Bar()" was executed from another compilation unit, then JLS 15.9.2 would determine that there is an immediately enclosing instance of the new Bar object. The immediately enclosing instance must be passed to Bar's constructor, which must have a formal parameter to receive it, but 15.9.3 does not specify the argument to Bar's constructor and 8.8.9 does not implicitly declare the constructor parameter.

      Zooming out:

      - There is an immediately enclosing instance of an anonymous class, a local class, and a private inner member class (unless the class or its CICE is in a static context), but it need not be transmitted to the constructor of the class through a formal parameter.

      - There is an immediately enclosing instance of a non-private inner member class (unless its CICE is in a static context), and it _must_ be transmitted to the constructor of the class through a formal parameter.

      The rule for 15.9.3 should be:

      - If C is an anonymous class with direct superclass S, then:
        -- If S is not an inner class, or if S is a local class that occurs in a static context, then the arguments to the constructor are the arguments in the argument list of the CICE, in the order they appear in the CICE.
        -- Otherwise, the first argument to the constructor is the immediately enclosing instance of i with respect to S, and the subsequent arguments to the constructor are the arguments in the argument list of the CICE, in the order they appear in the CICE.
        /* These two clauses are semantically equivalent to JLS7. They are just reorganized to match the clauses specifying the implicitly declared constructor of an anonymous class in 15.9.5.1. */

      - If C is a local class or a private inner member class, then the arguments to the constructor are the arguments in the argument list of the CICE, in the order they appear in the CICE.
        /* This clause is new. The local class may have an immediately enclosing instance, and the private inner member class definitely has, but we don't mandate how the instance is transmitted to the constructor. */

      - If C is a non-private inner member class, then the first argument to its constructor is the immediately enclosing instance of i, and the subsequent arguments to its constructor are the arguments in the argument list of the CICE, in the order they appear in the CICE.
        /* This clause is new. It needs to be matched by every constructor of an inner member class implicitly declaring a parameter to receive the immediately enclosing instance. See below. */

      *** Start sidebar 1 ***
      From JLS2 onwards, 13.1 matched the new clause "If C is a non-private inner member class, ..." by specifying that "the constructor of a non-private inner member class must be compiled such that it has as its first parameter, an additional implicit parameter representing the immediately enclosing instance". It's not clear if the implicit parameter is a "construct introduced by the compiler without a corresponding construct in source code" - if it is, it would have to be marked synthetic by a separate rule in 13.1, but there were no parameter flags to express synthetic-ness in the days of JLS2. In Java SE 8, I think we are free to flag the "implicit parameter" as best we think. The right thing is to specify an implicitly declared in 8.8.1 (see below), so that it's flagged as ACC_MANDATED, and remove the obscure 13.1 clause.
      *** End sidebar 1 ***

      *** Start sidebar 2 ***
      It is redundant for 15.9.3 to pass the immediately enclosing instance of i with respect to S to the constructor of an anonymous class whose superclass is either a private inner member class or a local class not in a static context. Similarly, it is redundant for 15.9.5.1 to specify that the constructor of this anonymous class has a first formal parameter to receive the instance. The following program generates class files that exhibit the redundant argument and parameter:

      class Foo {
        void m() {
          class Bar {} /* Local class */

          new Bar() { /* Specified constructor and first formal parameter: Foo$1(Foo) {...} */ };
        }
      }

      Class Bar is necessarily in the same compilation unit as the CICE, so a compiler could transmit the instance to the new C object in a proprietary manner. But there is no point in "un-mandating" things in 15.9.3 and 15.9.5.1 now.
      *** End sidebar 2 ***

      To ensure that every constructor of an inner member class has the parameter mentioned above, 8.8.1 "Formal Parameters" must say:

      - The constructor of a non-private inner member class implicitly declares, as the first formal parameter, a variable representing the immediately enclosing instance of the class.

      And in 8.8.9 "Default Constructor":

      - The default constructor of a non-private inner member class implicitly declares one formal parameter representing the immediately enclosing instance of the class.

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

              Created:
              Updated:
              Resolved: