🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.jbuilder.java.language
Article #663

Re: Nested Class structure

#663
From: John McGrath [TeamB]
Date: Thu, 06 Jan 2005 11:02
132 lines
6153 bytes
On 1/3/2005 at 1:11:45 PM, Eric wrote:

> It will compile in JB9 Enterprise, but will not compile in JB2005 
> Enterprise.  I am using the same JDK for both JB9 & JB2005 (1.4.2).

I suspect that you are actually compiling with JDK 1.4.1 rather than 1.4.2
when you compile under JBuilder 9.  By default, JB9 used the javac
compiler from its host JDK rather than from the project JDK, so you may be
using the javac from JDK 1.4.1, but compiling against the class libraries
from JDK 1.4.2.

You could change this under Project Properties | Build | Java | Compiler,
although I do not think it is a good idea to do that.  If there is a
problem with the code, I do not think it makes sense to "fix" it by
reverting to an older compiler that does not detect the problem.

> In JB2005 I get the following error:
> "A.java": cannot reference this before supertype constructor has been
> called at line 9, column 19
> 
> I have the following nested class structure:
> 
> public class A {
>     public A() {}
> 
>     public class B extends A{
>         public B(){}
>     }
> 
>     public class C extends B{
>         public C(){}                  // <- error happens here
>     }
> }

Wow!  An inner class whose enclosing class instance is also its
superclass, and then throw in a subclass that is also an inner class to
boot.

[Imitating Michael Palin's T. F. Gumby]  My brain hurts!

Take a look at how subclasses and inner classes work.  When you declare a
subclass, the subclass constructor always calls the superclass
constructor.  [For this discussion, we can ignore the exceptions - when
you explicitly call another constructor or where there is no superclass -
i.e. Object.]
So if you do not explicitly call a superclass constructor, the compiler
will insert this call.  So the constructor B above is equivalent to:

      public B() {
         super();   // Calls A()
      }

Now, since B is an inner class of A, it is allowed to reference the
members of the enclosing instance.  The way this happens is that the
compiler generates a pointer to the enclosing instance and passes it as a
hidden argument to the constructor.  So a more or less equivalent view of
class B is:

   public static class B extends A {
      A ei;  // reference to enclosing instance
      public B( A _ei ) {
         this.ei = _ei;
      }
   }

Whenever you call the constructor of an inner class, you need to provide
the reference to the enclosing instance.  If you use an unqualified call
of the constructor from the enclosing class, the constructor automatically
provides the 'this' pointer as the enclosing instance.  If not, you would
need to qualify the call with an expression like: a.new B();

Of course, the superclass constructor is also there, so the constructor is
now:

      public B( A _ei ) {
         super();   // Calls A()
         this.ei = _ei;
      }

If we apply the same logic to C, we get the following:

   public static class C extends B {
      A ei;  // reference to enclosing instance
      public C( A _ei ) {
         super();   // Calls B()
         this.ei = _ei;
      }
   }

But this code also has to provide the enclosing instance for the B()
constructor.  JLS 15.9.2 seems to suggest that the value provided would be
the hidden enclosing instance variable 'ei', so the constructor really
looks like this:

      public C( A _ei ) {
         super( this.ei );   // Calls B()
         this.ei = _ei;
      }

You can see the problem with this code: the superclass constructor is
always called before *any* subclass initializations are performed, and it
is illegal to reference any subclass members before that call - i.e. in
the arguments.  But in the code above, the superclass constructor argument
references the hidden instance member this.ei, before this.ei has been
initialized.

I suspect that JLS 15.9.2 was loosely interpreted before Java 1.4.2, so
that the argument _ei was passed to the superclass constructor instead of
the enclosing instance variable this.ei, and that the language lawyers
decided that the spec should be followed more closely.  I could not find
anything in the Java 1.4.2 release notes that says this, so I am just
guessing.

FWIW, I can see no reason that it should not be allowed to pass the _ei
argument.  But at the same time, it does not bother me much, since I do
not think that a class structure like this is a very good idea.

I am guessing that you do not really need to define classes B and C as
*inner* classes of A.  In the example you posted, there is no reason to do
this, since neither B or C contain any references to instance members of
A.  If that is the case, you could change B and C to non-inner nested
classes.  In other words, add the keyword "static" to the class
definitions.  If you do that, the error should go away.

-- 
Regards,

John McGrath [TeamB]

---------------------------------------------------
Before sending me e-mail, please read:
    http://www.JPMcGrath.net/newsgroups/e-mail.html
Technical Details
Message-ID: <xn0dwxc8f4xtlec009@newsgroups.borland.com>
Path: arc1-ca.pugleaf.net!g2news1.google.com!news1.google.com!proxad.net!gatel-ffm!gatel-ffm!213.73.255.4.MISMATCH!newsfeed.multikabel.nl!news2.euro.net!216.196.110.149.MISMATCH!border2.nntp.ams.giganews.com!nntp.giganews.com!pe2.news.blueyonder.co.uk!blueyonder!news-peer-test!btnet!newsfeed.bt.es!caladan.landsraad.net!newsgroups.borland.com!not-for-mail
References: <41d98a9a$1@newsgroups.borland.com>

Show Full Headers
Complete Article Headers
X-Google-Thread: f74b3,1d09f1c6e3c1ffa2
X-Google-Attributes: gidf74b3,public
X-Google-Language: ENGLISH,ASCII-7-bit
From: "John McGrath  [TeamB]" <ng-b@JPMcGrath.net>
Subject: Re: Nested Class structure
Newsgroups: borland.public.jbuilder.java.language
References: <41d98a9a$1@newsgroups.borland.com>
User-Agent: XanaNews/1.17.1.2
Message-ID: <xn0dwxc8f4xtlec009@newsgroups.borland.com>
X-Ref: newsgroups.borland.com ~XNS:000000E7
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-15
NNTP-Posting-Host: 141.158.234.226
Date: 6 Jan 2005 03:02:35 -0800
X-Trace: newsgroups.borland.com 1105009355 141.158.234.226 (6 Jan 2005 03:02:35 -0800)
Lines: 132
X-Authenticated-User: jpmcgrath
Path: arc1-ca.pugleaf.net!g2news1.google.com!news1.google.com!proxad.net!gatel-ffm!gatel-ffm!213.73.255.4.MISMATCH!newsfeed.multikabel.nl!news2.euro.net!216.196.110.149.MISMATCH!border2.nntp.ams.giganews.com!nntp.giganews.com!pe2.news.blueyonder.co.uk!blueyonder!news-peer-test!btnet!newsfeed.bt.es!caladan.landsraad.net!newsgroups.borland.com!not-for-mail