how to pass this before supertype constructor has been called

P

Paul J. Lucas

Given:

// Other.java
class Other {
Other( Base b ) {
m_b = b;
}
final Base m_b;
}

// Base.java
class Base {
Base( Other o ) {
m_o = o;
}
final Other m_o;
}

// Derived.java
class Derived extends Base {
static class Inner1 extends Other {
Inner1( Base b ) {
super( b );
}
static class Inner1a extends Other {
// ...
}
}
static class Inner2 extends Other {
// ...
}

Derived() {
super( new Inner1( this ) ); // illegal
}
}

There are many inner classes derived from Other. All of them
need to have a reference to their outermost creating instance
of Derived. (This is machine-generated code in case you're
wondering.) But it's illegal to pass "this" as shown above
(although there is no reason for this restriction since it's
just an address in memory which is already known. C++ has no
such restriction.)

How can I get what I want in Java?

- Paul
 
M

Mustafa Aydin

Paul J. Lucas said:
Given:

// Other.java
class Other {
Other( Base b ) {
m_b = b;
}
final Base m_b;
}

// Base.java
class Base {
Base( Other o ) {
m_o = o;
}
final Other m_o;
}

// Derived.java
class Derived extends Base {
static class Inner1 extends Other {
Inner1( Base b ) {
super( b );
}
static class Inner1a extends Other {
// ...
}
}
static class Inner2 extends Other {
// ...
}

Derived() {
super( new Inner1( this ) ); // illegal
}
}

There are many inner classes derived from Other. All of them
need to have a reference to their outermost creating instance
of Derived. (This is machine-generated code in case you're
wondering.) But it's illegal to pass "this" as shown above
(although there is no reason for this restriction since it's
just an address in memory which is already known. C++ has no
such restriction.)

How can I get what I want in Java?

- Paul


I'm not sure if there really is no reason to permit the usage
of "this" before the object is fully created (although you really pass
only an address).

You say the code is machine-generated!? So the "machine" is
responsible to generate legal java code. On the other hand
if this "machine"-program was adaptet from an existing
C++ source you can slightly change it to produce a setter
method that actually does the setting. Likely as:


// Other.java
class Other {
void setBase(Base b) {m_b = b;}
Base m_b;
}

// Base.java
class Base {
void setOther(Other other) {m_o = other;}
Other m_o;
}

// Derived.java
class Derived extends Base {
static class Inner1 extends Other {
static class Inner1a extends Other {
}
}
static class Inner2 extends Other {
}

Derived() {
//super( new Inner1( this ) ); // illegal
Other inner1 = new Inner1();
inner1.setBase(this);
setOther(inner1);
}
}

This uses a little more code but it doesn't matter if it's
machine-generated.

The only problem is that the references are no longer final and therefore
should be private.

In order to avoid later invocations of setXXX(...) the setXXX methods
should test if the instance variable is still null

Bye
Mustafa
 
P

Paul J. Lucas

Mustafa Aydin said:
You say the code is machine-generated!? So the "machine" is
responsible to generate legal java code.

Yes I know: I'm the one trying to write the machine to do just
that.
On the other hand if this "machine"-program was adaptet from an existing C++
source you can slightly change it to produce a setter method that actually
does the setting.

Yes, but that's a stupid hack.
The only problem is that the references are no longer final and therefore
should be private.

Right. I was hoping to avoid that ugly hack, however.

- Paul
 
J

John C. Bollinger

Paul said:
Given:

// Other.java
class Other {
Other( Base b ) {
m_b = b;
}
final Base m_b;
}

// Base.java
class Base {
Base( Other o ) {
m_o = o;
}
final Other m_o;
}

// Derived.java
class Derived extends Base {
static class Inner1 extends Other {
Inner1( Base b ) {
super( b );
}
static class Inner1a extends Other {
// ...
}
}
static class Inner2 extends Other {
// ...
}

Derived() {
super( new Inner1( this ) ); // illegal
}
}

There are many inner classes derived from Other. All of them
need to have a reference to their outermost creating instance
of Derived. (This is machine-generated code in case you're
wondering.) But it's illegal to pass "this" as shown above
(although there is no reason for this restriction since it's
just an address in memory which is already known. C++ has no
such restriction.)

C++ has no restrictions against many things that can in fact be harmful.
By design, Java is much more careful. In the parts of the example
that show real code, you can be confident that the Derived instance is
not used unsafely before it is fully initialized, but one cannot make
such an assumption in general.
How can I get what I want in Java?

It depends on what it is you want. You cannot do exactly what you are
trying to do, but you already knew that.

It might be that making the nested classes be inner classes (by removing
the "static" modifiers) would solve the problem while simultaneously
simplifying the object construction process. An inner class instance
automatically has references (hidden, yet accessible) to all containing
instances, and can directly access those instances' members.


John Bollinger
(e-mail address removed)
 
P

Paul J. Lucas

John C. Bollinger said:
C++ has no restrictions against many things that can in fact be harmful. By
design, Java is much more careful.

I'm not going to get into a langauge war with you. Suffice it
to say that *I* should be the one allowed to make such
decisions.

Either you have a solution to my problem of you don't.
In the parts of the example that show real code, you can be confident that
the Derived instance is not used unsafely before it is fully initialized ...

How can the Base class use it in any way whatsoever? It's
totally unaware of the derived class.
It might be that making the nested classes be inner classes (by removing
the "static" modifiers) would solve the problem while simultaneously
simplifying the object construction process.

Did you try it? It doesn't work for the same reason.
An inner class instance automatically has references (hidden, yet accessible)
to all containing instances, and can directly access those instances'
members.

Yes, I already knew that. How else would I have known to put
"static" there in the first place? Clearly I had to know what
the default is and what "static" does.

- Paul
 
J

John C. Bollinger

Paul said:
I'm not going to get into a langauge war with you. Suffice it
to say that *I* should be the one allowed to make such
decisions.

And you make several such decisions by choosing Java.

I apologize that you found my comment inflammatory; perhaps "dangerous"
would have been a better word than "harmful". In any event, the point
is that Java is by design rather more picky and restrictive than is C++
in several areas; this is widely recognized and has both advantages and
disadvantages.
Either you have a solution to my problem of you don't.

That sounds like a pretty safe bet. :)
How can the Base class use it in any way whatsoever? It's
totally unaware of the derived class.

Base could in fact use it if it invoked a method that Derived had
overridden -- a dangerous practice that is nevertheless allowed in Java.
Base could also use it indirectly via the Other instance supplied to
its constructor. But I was also talking about the Inner1, Inner2, etc.
constructors using it.
Did you try it? It doesn't work for the same reason.

No, I didn't try it. And I wrote that it _might_ work. I'm sorry that
it didn't.

I take it you don't intend to honor my invoice?
Yes, I already knew that. How else would I have known to put
"static" there in the first place? Clearly I had to know what
the default is and what "static" does.

Yes, there is only one possible explanation for the static modifiers on
those classes. There is no chance that they were copied from some
not-necessarilly-relevant and not fully understood example. There is no
chance that your code generator puts them in without good reason. There
is no chance that you misunderstand the meaning of "static" in Java,
which does not precisely match its meaning in C++ (with which you
expressed familiarity). Of course all those who post questions to this
forum are already well versed in Java. (Otherwise, how could they come
up with such clever questions?)




With regard to your actual problem, here is an inner-class-based
solution that works for me:


class Other {
}

abstract class Base {
final Other other;

Base() {
other = getOther();
}

abstract protected Other getOther();
}

class Derived extends Base {
class Inner1 extends Other {
}

public Derived() {
}

protected Other getOther() {
return new Inner1();
}
}


It does use the dangerous practice described above of the superclass'
constructor invoking a method of the derived class. The Inner1
constructor must not depend on Derived's state if this is to work (but
otherwise no solution of this general kind can work). A better solution
might be to redesign the object relationships, but more information
about the purpose and usage of the classes involved would be necessary
to make that determination.


John Bollinger
(e-mail address removed)
 
D

Dale King

Paul J. Lucas said:
Given:

// Other.java
class Other {
Other( Base b ) {
m_b = b;
}
final Base m_b;
}

// Base.java
class Base {
Base( Other o ) {
m_o = o;
}
final Other m_o;
}


The derived and inner classes are really not the issue here. Basically you
have a chicken and an egg problem with these two classes. You cannot have an
instance of Other before you have an instance of Base and you cannot have an
instance of Base before you have an instance of Other.

There is no way out of that circularity outside of using null to create an
instance referring to no instance. Trying to get a reference to an
uninitialized instance by subclassing is not allowed of course and rightly
so..

You need to rethink your design. The java.io classes PipedInputStream and
PipedOutputStream have a similar scenario and you should take a look at how
they solve it. You basically have to allow one end of the two classes to be
able to be constructed before the other.
 
A

Andrea Desole

C++ has no restrictions against many things that can in fact be harmful.
By design, Java is much more careful. In the parts of the example that
show real code, you can be confident that the Derived instance is not
used unsafely before it is fully initialized, but one cannot make such
an assumption in general.

There is something I don't get. For the same reason it should then be
necessary to disable polymorphism in the constructor, but as far as I
know polymorphism is not disabled. That is, in the constructor of the
derived class you can use members that are not yet initialized.
I don't see a big difference here.

Andrea
 
J

John C. Bollinger

Andrea said:
There is something I don't get. For the same reason it should then be
necessary to disable polymorphism in the constructor, but as far as I
know polymorphism is not disabled. That is, in the constructor of the
derived class you can use members that are not yet initialized.
I don't see a big difference here.

If you mean that the constructor of the base class can manipulate
uninitialized members of the derived class via polymorphic methods of
the derived class then you're right, it's an inconsistency in the
language design. I suspect that it was allowed either as an oversight
or to simplify JVM / compiler implementation. Either way, it allows
working around the language restriction in this case, which may or may
not be a good thing. It does require the cooperation of the derived
class, however, so there is at least some degree of protection.


John Bollinger
(e-mail address removed)
 
T

Tim Ward

John C. Bollinger said:
If you mean that the constructor of the base class can manipulate
uninitialized members of the derived class via polymorphic methods of
the derived class then you're right, it's an inconsistency in the
language design. I suspect that it was allowed either as an oversight
or to simplify JVM / compiler implementation. Either way, it allows
working around the language restriction in this case, which may or may
not be a good thing. It does require the cooperation of the derived
class, however, so there is at least some degree of protection.

Once you've worked out what's going on.

Try deriving from JTable, for example, and you'll find all sorts of your
derived class methods being called before the constructor has run. Sure, you
can put in protective code, to make sure these methods don't crash until
things have been properly intialised, but this protective code then, of
course, runs every time the derived methods are called giving a completely
unnecessary overhead.

The author of JTable appears to have failed to spot, or to have decided not
to adhere to, the suggested rule the one might consider avoiding calling
polymorphic methods in constructors.
 
P

Paul J. Lucas

John C. Bollinger said:
Paul J. Lucas wrote:
And you make several such decisions by choosing Java.

I didn't choose Java. I'm only implementing a Java version to
have broader appeal.
Base could in fact use it if it invoked a method that Derived had
overridden -- a dangerous practice that is nevertheless allowed in Java.

Yeah and that one seems contradictory to everything you said
earlier.
Yes, there is only one possible explanation for the static modifiers on
those classes. There is no chance that they were copied from some
not-necessarilly-relevant and not fully understood example. There is no
chance that your code generator puts them in without good reason.

I'm the one writing the code generator.
With regard to your actual problem, here is an inner-class-based
solution that works for me:

But it doesn't pass "this", so how is this a solution?

- Paul
 
P

Paul J. Lucas

Dale King said:
Basically you have a chicken and an egg problem with these two classes. You
cannot have an instance of Other before you have an instance of Base and you
cannot have an instance of Base before you have an instance of Other.

I never said I needed an "instance" of the derived class. All
I care about is its "this" reference which *is* known at the
time the Derived constructor is running. But Java simply
doesn't allow you to refer to it because of "safety."
You need to rethink your design.

You need to re-read my original question.

- Paul
 
D

Dale King

Paul J. Lucas said:
I never said I needed an "instance" of the derived class. All
I care about is its "this" reference which *is* known at the
time the Derived constructor is running. But Java simply
doesn't allow you to refer to it because of "safety."

Funny, but I don't see where I used the word derived at all in what you
quoted. I specifically said Base and Other. And no the this reference is not
known until the constructor is called. You essentially do not have an
instance of Base until its constructor is called and all its super class
constructors have finished.

Imagine if your Other class tried to use the Base reference in its
constructor. Base is totally uninitialized. There are no guarantees about
what would happen in this case. To make guarantees would place extra burden
on the implementer of the VM.

In this case safety is a good thing.
You need to re-read my original question.

No, I don't. I understand what you are requesting completely. You have a
chicken and the egg paradox and you think Java should let you get away with
referencing an unconstructed object as a way to solve the paradox. You are
wrong. Java should not let you do that. Your design is wrong.
 
D

Dale King

Dale King said:
classes. and

Funny, but I don't see where I used the word derived at all in what you
quoted. I specifically said Base and Other. And no the this reference is not
known until the constructor is called. You essentially do not have an
instance of Base until its constructor is called and all its super class
constructors have finished.

Imagine if your Other class tried to use the Base reference in its
constructor. Base is totally uninitialized. There are no guarantees about
what would happen in this case. To make guarantees would place extra burden
on the implementer of the VM.

In this case safety is a good thing.


I thought of another reason why what Paul is requesting is inherently
unsafe. Imagine if it were allowed to pass this before construction. In this
case Other stores that reference. What happens when the constructor actually
does run and it throws an exception? You could then have a reference to not
only an uninitialized instance but one whose constructor failed and whose
memory has actually been freed and is no longer even allocated!

Once again you have a logical paradox that is a problem in your design. The
problem is not that Java is safe. If you want help with correcting design
you have to explain what your design represents, not just abstract classes.
 
J

John C. Bollinger

Paul said:
But it doesn't pass "this", so how is this a solution?

As I wrote in a previous message, you cannot do exactly what you are
trying to do (i.e. pass "this" from within a class' constructor).
Period. The solution I offered provides a means to achieve an
equivalent goal, however.

You were attempting to construct two objects, each of which held a final
reference to the other, with the class of one being a nested class of
the class of the other. The solution I offered achieves precisely that.
If there are additional requirements that you have not disclosed then
please forgive me for not taking them into account.


John Bollinger
(e-mail address removed)
 
J

John C. Bollinger

Dale said:
I thought of another reason why what Paul is requesting is inherently
unsafe. Imagine if it were allowed to pass this before construction. In this
case Other stores that reference. What happens when the constructor actually
does run and it throws an exception? You could then have a reference to not
only an uninitialized instance but one whose constructor failed and whose
memory has actually been freed and is no longer even allocated!

Given that I offered a workaround that basically does allow this to be
passed before completion of the constructor, it occurred to me to test
out that scenario. I found the result a bit shocking. Here's the code:


class Other {
static Other lastOther;

final Base base;

Other(Base b) {
base = b;
Other.lastOther = this;
}

public void foo() {
base.foo();
}
}

abstract class Base {
private final Other other;

Base() {
other = getOther();
}

protected abstract Other getOther();

public void foo() {
System.out.println("Foo!");
}
}

class Derived extends Base {
class Inner extends Other {
Inner() {
super(Derived.this);
}
}

public Derived() {
throw new RuntimeException("Can't construct a Derived.");
}

protected Other getOther() {
return new Inner();
}
}

public class ReferenceTest {
public static void main(String[] args) {
try {
Derived d = new Derived();
} catch (RuntimeException re) {
System.out.println(re);
}
System.out.println("Class of lastOther.base is "
+ Other.lastOther.base.getClass());
Other.lastOther.foo();
}
}


Here is the result (Java 1.4.2):

D:\temp\testdir>java -cp . ReferenceTest
java.lang.RuntimeException: Can't construct a Derived.
Class of lastOther.base is class Derived
Foo!


Even though it is impossible to successfully construct a Derived, I can
nevertheless obtain a reference to one and even invoke methods on it by
using an inner class to convey the reference through the return value of
a polymorphic method. (Yikes! What a sentence!) I haven't yet found
anything in the JLS to forbid this, but I would sure be interested in
hearing about such a thing. Does anyone think this behavior is a defect
worth reporting? Is it already known? (My first inclination would be
to guess that it is.)


John Bollinger
(e-mail address removed)
 
A

Andrea Desole

Tim said:
Once you've worked out what's going on.

Try deriving from JTable, for example, and you'll find all sorts of your
derived class methods being called before the constructor has run. Sure, you
can put in protective code, to make sure these methods don't crash until
things have been properly intialised, but this protective code then, of
course, runs every time the derived methods are called giving a completely
unnecessary overhead.

I don't know how JTable works, but I agree. There is no difference
between enabling polymorphism and passing this in the constructor. In
either case you have to know exactly how the base class handles the
derived class, or you have to put in some code to protect the
consistency of your derived class.

Andrea
 
C

Chris Uppal

John said:
Given that I offered a workaround that basically does allow this to be
passed before completion of the constructor, it occurred to me to test
out that scenario. I found the result a bit shocking. Here's the code:
[snipped]
D:\temp\testdir>java -cp . ReferenceTest
java.lang.RuntimeException: Can't construct a Derived.
Class of lastOther.base is class Derived
Foo!

Very nasty!

The problem code can be significantly simplified (and so avoid some
red-herrings), thus:

===========================
class Base
{
static Base leaked;

Base()
{
leaked = this;
}

void foo()
{
System.out.println("Foo!");
}
}

class Derived extends Base
{
public Derived()
throws Exception
{
throw new Exception("Can't construct a Derived.");
}
}

public class RefTest
{
public static void main(String[] args)
{
try
{
Derived d = new Derived();
} catch (Exception ex)
{
System.out.println(ex);
}
System.out.println("Class of Base.leaked is "
+ Base.leaked.getClass());
Base.leaked.foo();
}
}
===========================
Does anyone think this behavior is a defect
worth reporting? Is it already known? (My first inclination would be
to guess that it is.)

I certainly think its a defect. I'd guess that it's known (in the simplified
form) already. I can't see any way to prevent it, though.

Note that the leaked reference is left permanently in the state that would be
seen transiently by methods of Derived that were called from Base's
constructor, so it's really a way to blow up a small glitch in the system into
a larger (or longer lived) one.

I've been trying to think of ways that this could be exploited to circumvent
security. So far, I haven't found anything -- one reason is that any state
guarantees that the Base constructor wants to enforce are set before the object
could be "frozen" by a derived constructor. One could possibly have some fun
with code like:

===========================
class Base
{
final Object blankFinal; // apparently *must* be set

Base()
{
this.log("Creating a new Base");
blankFinal = "is not null";
}

void log(String message)
{
System.out.println(message);
}
}

class LeakyException
extends RuntimeException
{
Base base;

LeakyException(String message, Base base)
{
super(message);
this.base = base;
}
}

class Drill
extends Base
{
void log(String message)
{
// ha ha!
throw new LeakyException("Woops!", this);
}
}

public class RefTest
{
public static void main(String[] args)
{
try
{
new Drill();
} catch (LeakyException ex)
{
System.out.println(ex);
System.out.println("leaked blankFinal is "
+ ex.base.blankFinal);
}
}
}
===========================

-- chris
 
P

Paul J. Lucas

Dale King said:
And no the this reference is not known until the constructor is called.

Of course it is. It has to be. The constructor has nothing to
do with it. For a class with neither base nor derived classes,
the steps are:

1. Programmer calls "new SomeObject()"
2. JVM allocates memory from the heap for sizeof( SomeObject ).
3. Calls SomeObject() constructor with "this" set to point to
memory allocated in step 2.
4. Programmer does stuff inside constructor code like
initialize member variables.

The only thing that is different if SomeObject has a base class,
is that it is up to the *programmer* in step 4 to call super().
The address of "this" MUST STILL BE KNOWN.
You have a chicken and the egg paradox

No I don't. I can do what I want in C++ just fine. As long as
I don't try to access anything *through* "this" I'm fine. It'd
perfectly safe. It's 100% portable. It just works.
and you think Java should let you get away with referencing an unconstructed
object as a way to solve the paradox. You are wrong. Java should not let you
do that.

It's not a paradox. Sorry you just can't see that.

- Paul
 
P

Paul J. Lucas

Dale King said:
What happens when the constructor actually does run and it throws an
exception?

Nothing at all.
You could then have a reference to not only an uninitialized instance but one
whose constructor failed and whose memory has actually been freed and is no
longer even allocated!

But the base class holding that reference doesn't exist either
since they're the same exact object. A derived instance has a
base instance inside it. Both their "this" pointers point to
the exact same memory location. If the derived object has been
freed, then (obviously) the base object (inside it) has also.
Once again you have a logical paradox that is a problem in your design.

Once again you don't see that there's no paradox.

- Paul
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top