> This is mostly a sanity check. In the jdk I am using, it appears that
> inner classes see a null outer "this" pointer if the inner object is
> constructed during the outer <init>. Is this even remotely reasonable?

Signature
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
>>This is mostly a sanity check. In the jdk I am using, it appears that
>>inner classes see a null outer "this" pointer if the inner object is
[quoted text clipped - 7 lines]
> reference from the VM's standpoint, and it will be initialized in or
> just prior to the constructor, just like anything else.
I'd like to see the real code. My best guess as to what he meant does
not exhibit the behavior he described. Here's my version of the code:
class Outer {
class Inner {
public Inner() {
Outer.this.hello();
}
}
public Outer() {
new Inner();
}
void hello() {
System.out.println("hello");
}
public static void main(String[] args) {
new Outer();
}
}
When I run it (Sun JRE 1.5.0_02), it prints "hello" and exits normally,
as I expected it would.
When a constructor or instance initializer runs, it has access to a
valid "this" reference (per JLS). I haven't found the same level of
assurance in the JLS for a qualified "this", but I do find a flat "Any
lexically enclosing instance can be referred to by explicitly qualifying
the keyword this" (JLS 15.8.4). There is no particular reason why the
qualified "this" reference(s) should be unavailable on account of inner
class instantiation happening in a constructor. In fact, I assert that
the Java compiler is in error in successfully compiling the above code
if it cannot or does not ensure that the Inner constructor has a valid
value for Outer.this.
It is an *entirely* different story, however, if the inner class'
constructor assumes that its containing instance is fully initialized,
and thus attempts to directly or indirectly read or manipulate its
member variables. For instance:
class Outer2 {
PrintStream out;
class Inner2 {
public Inner2() {
Outer2.this.hello();
}
}
public Outer2() {
new Inner2();
out = System.out;
}
void hello() {
out.println("hello");
}
public static void main(String[] args) {
new Outer2();
}
}
This version of the program quite expectedly throws a
NullPointerException from Outer2.hello().

Signature
John Bollinger
jobollin@indiana.edu
Chris Smith - 23 Dec 2005 04:09 GMT
> When a constructor or instance initializer runs, it has access to a
> valid "this" reference (per JLS). I haven't found the same level of
[quoted text clipped - 3 lines]
> qualified "this" reference(s) should be unavailable on account of inner
> class instantiation happening in a constructor.
I agree that:
1. The JLS is at best unclear, and at worst fails to match the
implementation, on whether a qualified this reference is guaranteed to
point to an object at all times.
2. The mere creation of an inner class instance from a constructor is
not sufficient to cause the problem.
Here's some code that, correctly or not, does manage to observe a null
qualified this pointer from an inner class in Java.
class Outer
{
public Outer()
{
test();
}
public void test()
{
}
public class Inner extends Outer
{
public void test()
{
System.out.println(Outer.this);
}
}
public static void main(String[] args)
{
new Inner();
}
}

Signature
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
Chris Uppal - 23 Dec 2005 09:33 GMT
> Here's some code that, correctly or not, does manage to observe a null
> qualified this pointer from an inner class in Java.
>
> class Outer
> {
[...]
> public class Inner extends Outer
> {
FWIW, this would not be the first bug to surface in connection with inner
classes that extent their outers.
> public static void main(String[] args)
> {
> new Inner();
> }
I'm surprised that compiles. It seems an obvious semantic error. And, in
fact, it doesn't compile for me; which compiler are you using (I'm using the
javac from 1.5.0-b64) ?
-- chris
Chris Smith - 23 Dec 2005 14:32 GMT
> I'm surprised that compiles. It seems an obvious semantic error. And, in
> fact, it doesn't compile for me; which compiler are you using (I'm using the
> javac from 1.5.0-b64) ?
Sorry, I was in a hurry. Let me try this again, and compile it this
time.
Here's what I meant to write:
abstract class Base
{
public Base()
{
test();
}
public abstract void test();
}
public class Outer
{
public class Inner extends Base
{
@Override
public void test()
{
System.out.print(Outer.this);
}
}
public static void main(String[] args)
{
new Outer().new Inner();
}
}
However, it doesn't behave as I expected. Your other post explains
this; apparently, this was fixed as a bug in 1.4? I must have missed
that change.

Signature
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
Roedy Green - 23 Dec 2005 12:44 GMT
>class Outer
>{
[quoted text clipped - 20 lines]
> }
>}
Since Inner in an inner class of Outer, you should not be allowed to
instantiate it except in an instance method of Outer. That is a
compiler bug, is it not?

Signature
Canadian Mind Products, Roedy Green.
http://mindprod.com Java custom programming, consulting and coaching.
Chris Uppal - 23 Dec 2005 09:28 GMT
> In fact, I assert that
> the Java compiler is in error in successfully compiling the above code
> if it cannot or does not ensure that the Inner constructor has a valid
> value for Outer.this.
I agree, but it hasn't always been able to ensure that. The code it generates
these days was disallowed by pre-1.4 verifiers (because it assigns the
synthetic $outer field before calling the superclass constructor, which is
normally illegal). So the following code will print hello if compiled with:
javac -g -source 1.4 -target 1.4 Outer.java
but will NPE if compiled with:
javac -g -source 1.3 -target 1.3 Outer.java
It may be that the OP is in a 1.3-based environment ?
-- chris
===== example code =======
abstract class Helper
{
Helper()
{
doit();
}
abstract void doit();
}
class Outer
{
class Inner
extends Helper
{
void
doit()
{
Outer.this.hello();
}
}
public Outer()
{
new Inner();
}
void
hello()
{
System.out.println("hello");
}
public static void
main(String[] args)
{
new Outer();
}
}
Thomas Hawtin - 23 Dec 2005 10:45 GMT
> It may be that the OP is in a 1.3-based environment ?
Or, perhaps more likely, just accepting the (badly chosen) default
-target in 1.4.
Tom Hawtin

Signature
Unemployed English Java programmer
http://jroller.com/page/tackline/