how to pass this before supertype constructor has been called  
Author Message
Chris Smith





PostPosted: 2003-12-4 0:56:00 Top

java-programmer, how to pass this before supertype constructor has been called Paul J. Lucas wrote:
> 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.

Paul, there's really no answer then, other than "go use C++ and do it".
You can't do what you're asking in Java. Your winning an argument isn't
going to change your compiler and magically let you do it. You will
simply need to allow the initialization to be completed from within the
derived class's constructor, because you can't just reference this when
defining the parameters to the superclass constructor.

Maybe you think that you should be able to do so, and of course it would
be possible to define a language similar to Java in which you could, but
when you're working in Java, you can't.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
Chris Smith





PostPosted: 2003-12-4 0:56:00 Top

java-programmer >> how to pass this before supertype constructor has been called Paul J. Lucas wrote:
> 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.

Paul, there's really no answer then, other than "go use C++ and do it".
You can't do what you're asking in Java. Your winning an argument isn't
going to change your compiler and magically let you do it. You will
simply need to allow the initialization to be completed from within the
derived class's constructor, because you can't just reference this when
defining the parameters to the superclass constructor.

Maybe you think that you should be able to do so, and of course it would
be possible to define a language similar to Java in which you could, but
when you're working in Java, you can't.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
Dale King





PostPosted: 2003-12-4 1:48:00 Top

java-programmer >> how to pass this before supertype constructor has been called "Paul J. Lucas" <email***@***.com> wrote in message
news:8pozb.32101$F%email***@***.com...

On a side note, completely by coicidence, I downloaded txt2pdbdoc only to
discover that it was written by a certain Paul J. Lucas. I may convert it to
Java for my needs.

> Dale King <email***@***.com> wrote:
>
> > 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.

And that is making some assumptions about how a VM works that may not
guaranteed by the spec.

> 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.

But is in an unknown state and is unsafe to use.

> > 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 the fact that C++ lets you access the pointer before it is initialized
does not mean the paradox doesn't exist. On the flip side C++ doesn't let
you access member functions polymorphically from a constructor. In this
regard C++ is safer than Java. Unfortunately that makes it much less
convenient.

> > 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.

Yes it is. Sorry you just can't see that. Once again remove the whole
subclass thing and just look at it as two classes that want to have final
instance references to each other. I'll make them final to remove the
possibility of subclassing:

final class A
{
final B b;
public A( B b )
{
this.b = b;
}
}

final class B
{
final A a;
public B( A a )
{
this.a = a;
}
}

That is a chicken and egg paradox. There is absolutely no way that you can
create instances of these two classes so that they refer to each other. You
can create instances of these classes, but not so that they reference each
other.

You feel that you should be able to get around this paradox by subclassing
one of them, but that still does not eliminate the fact that the paradox
exists. C++ gives you a way out of the paradox, but the paradox still
exists.

I agree with Chris, that you can argue whether you should be allowed to get
the this pointer before the instance is initialized until you are blue in
the face, it doesn't change reality. The only reason you want it is because
you have created a paradoxical design. The solution is to fix your design so
that it is not dependent on the language allowing you to do things that are
inherently unsafe.

 
 
John C. Bollinger





PostPosted: 2003-12-4 22:38:00 Top

java-programmer >> how to pass this before supertype constructor has been called Paul J. Lucas wrote:

> Dale King <email***@***.com> wrote:
>
>
>>What happens when the constructor actually does run and it throws an
>>exception?
>
>
> Nothing at all.

Presumably this is either a hope, a specification, or an assumption. It
is not, however, the actual result.

>>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.

Java does not have pointers. It has references, which serve many of the
same roles, but no pointers. The difference is not academic, and may be
part of what is causing you such apparent frustration. For example,
there is no inherent logical inconsistency with any particular pointer
referring any particular place in memory, but there _is_ a logical
inconsistency with a reference whose referrent does not exist or has not
yet been fully constructed.

You are also missing Dale's point. He is describing a situation where
(a C++ implementation of) your design could potentially produce, hold,
and use rogue pointers. That would be a serious concern for program
stability and perhaps even system security. Perhaps it would never
happen in your particular app -- I don't know, as you have only provided
a schematic description. But even if not, who's to say that some future
modification by a developer not as familiar with your app's innards
(which could even be yourself, two years hence) would not introduce such
a problem?

The situation with Java is a bit different, I think. After analyzing my
example of the problem (one branch to your left in this thread) and
thinking about how the JVM works, my conclusion is that the worst that
can happen on the Java side is that you end up with a reference to an
object whose initialization was aborted midway. This is not equivalent
to a rogue pointer, because the object does exist, and will continue to
exist at least until it becomes unreachable from any running thread.
Its state may not be consistent, however, and use of the thing will not
be likely to reliably produce the expected results.

>>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.

Whether or not it is a paradox, it _is_ a problem in your design, both
in Java and in C++. In the latter language the program evidently works,
but that does not validate the design quality. It is inherently unsafe
to pass around pointers / references to partially constructed objects,
and Java intentionally makes it difficult (albeit not impossible) to do so.

In your case, you have two classes of objects so tightly coupled
together that instances must come in pairs with each member of the pair
holding a final reference to the other. Good OOD principles call for
these things to be either combined into one or decoupled from each other.

One way of decoupling the objects would be to factor the links out into
a seperate object -- some kind of container that holds final references
to both of the others. Some of the code would need to go along to the
container too. Another, simpler way would be to do exactly as Dale
suggested, and assign one of the references after construction instead
of during. That doesn't achieve the same level of decoupling, but it's
better than what you have now. There are probably other, more
appropriate approaches as well, but they would depend on the nature and
roles of the classes involved.


John Bollinger
email***@***.com

 
 
Paul J. Lucas





PostPosted: 2003-12-5 1:21:00 Top

java-programmer >> how to pass this before supertype constructor has been called John C. Bollinger <email***@***.com> wrote:

> Java does not have pointers. It has references, which serve many of the
> same roles, but no pointers.

*eyeroll* On the machine-code level, which even Java must
ultimaty run at, there are no references, only pointers. A
reference is implemented as a pointer. How is it that you can
get a "Null reference exception" then? It's really a null
pointer just like in C++ or C, just with linguitsic sugar
wrapped around it.

> For example, there is no inherent logical inconsistency with any particular
> pointer referring any particular place in memory, but there _is_ a logical
> inconsistency with a reference whose referrent does not exist or has not yet
> been fully constructed.

And, even if I grant you the above, for the case at hand, it's
irrelevant, since (for something like the 6th time now): I'm not
*using* the reference. I'm just storing it.

> You are also missing Dale's point. He is describing a situation where
> (a C++ implementation of) your design could potentially produce, hold,
> and use rogue pointers.

It can't use them unless I (the application programmer) access
something through "this". As long as "this" is used only as a
rvalue, everything is fine.

> That would be a serious concern for program stability and perhaps even system
> security.

Hogwash. Instability comes from inconsistent results based on
unspecified behavior. There is no such thing (at least in C++)
about using "this" *at* *any* *time* as an rvalue.

> Perhaps it would never happen in your particular app -- I don't know, as you
> have only provided a schematic description.

If I say (for the 7th time now) that I only store a copy of
"this", then that's all the information that's needed.

> But even if not, who's to say that some future modification by a developer
> not as familiar with your app's innards (which could even be yourself, two
> years hence) would not introduce such a problem?

I don't care about that.

> After analyzing my example of the problem (one branch to your left in this
> thread) and thinking about how the JVM works, my conclusion is that the worst
> that can happen on the Java side is that you end up with a reference to an
> object whose initialization was aborted midway.

That's nice, but, again, irrelevant because "this" was never
going to be used during a successful construction and obviously
not during an unsuccessful one.

> Its state may not be consistent, however, and use of the thing will not
> be likely to reliably produce the expected results.

There you go again: THERE IS NO "use of the thing." IT'S NOT
USED IN THE CONSTRUCTOR, DAMMIT! Why is that so freaking hard
for you to understand?

> Whether or not it is a paradox, it _is_ a problem in your design, both
> in Java and in C++.

No it isn't. It's perfectly legal and stable in C++.

> It is inherently unsafe to pass around pointers / references to partially
> constructed objects, and Java intentionally makes it difficult (albeit not
> impossible) to do so.

And I, as a professional (and damned good) programmer know when
I can safely use them. I don't need Gosling to protect me from
myself.

- Paul
 
 
Paul J. Lucas





PostPosted: 2003-12-5 1:23:00 Top

java-programmer >> how to pass this before supertype constructor has been called Chris Smith <email***@***.com> wrote:

> Paul, there's really no answer then, other than "go use C++ and do it".

I already did: I'm now in the process or porting a perfectly
working C++ application to Java.

> You can't do what you're asking in Java.

That's all you needed to say. Had you said it, this thread
would have ended days ago.

- Paul
 
 
Paul J. Lucas





PostPosted: 2003-12-5 1:26:00 Top

java-programmer >> how to pass this before supertype constructor has been called Dale King <email***@***.com> wrote:
> "Paul J. Lucas" <email***@***.com> wrote in message
> news:8pozb.32101$F%email***@***.com...
>
> On a side note, completely by coicidence, I downloaded txt2pdbdoc only to
> discover that it was written by a certain Paul J. Lucas.

Yes, I've been around.

> I may convert it to Java for my needs.

1. I'm about to release a minor update/bug-fix (1.4.4).

2. I don't see the point in converting it to Java, but it's
your time to waste, so knock yourself out.

3. Remember to adhere to the GPL.

- Paul
 
 
John C. Bollinger





PostPosted: 2003-12-5 4:43:00 Top

java-programmer >> how to pass this before supertype constructor has been called Paul J. Lucas wrote:

> Chris Smith <email***@***.com> wrote:

[...]

>>You can't do what you're asking in Java.
>
>
> That's all you needed to say. Had you said it, this thread
> would have ended days ago.

Huh? I said that in my very first response in this thread, and
reiterated it later. I also gave you a workaround (ugly though it be).

Or do you mean it had to be _Chris_ who said you couldn't do what you
wanted? :^)


John Bollinger
email***@***.com

 
 
John C. Bollinger





PostPosted: 2003-12-5 5:59:00 Top

java-programmer >> how to pass this before supertype constructor has been called Paul J. Lucas wrote:

> John C. Bollinger <email***@***.com> wrote:
>
>
>>Java does not have pointers. It has references, which serve many of the
>>same roles, but no pointers.
>
>
> *eyeroll* On the machine-code level, which even Java must
> ultimaty run at, there are no references, only pointers. A
> reference is implemented as a pointer. How is it that you can
> get a "Null reference exception" then? It's really a null
> pointer just like in C++ or C, just with linguitsic sugar
> wrapped around it.

If you want machine code then write in machine code. If you don't like
the semantics of Java then don't write in Java. When you do write in
Java, you don't have pointers at your disposal, regardless of how
references are implemented in the JVM. You don't have them in Fortran
77, either, even though there are surely memory addresses being passed
around and used in the compiled machine code. The Java Language and VM
specs do not specify many particulars of the implementation of
references, and it is not safe to assume that on any particular VM they
are simply lightly-wrapped pointers. It is certainly not safe to assume
that on every VM they are implemented as lightly-wrapped pointers.

>>For example, there is no inherent logical inconsistency with any particular
>>pointer referring any particular place in memory, but there _is_ a logical
>>inconsistency with a reference whose referrent does not exist or has not yet
>>been fully constructed.
>
>
> And, even if I grant you the above, for the case at hand, it's
> irrelevant, since (for something like the 6th time now): I'm not
> *using* the reference. I'm just storing it.

Presumably you are storing it because you intend to use it later. Part
of Dale's argument was that if you store it before its referrent has
been fully constructed then it is very difficult to be certain in
general that when you do go back to use it -- whether in the
construction process or after -- the referrent will be in a valid state.
Furthermore, whether or not you use it in the constructor today, the
constructor could be modified to use it tomorrow, which needn't involve
recompilation of the derived classes.

>>But even if not, who's to say that some future modification by a developer
>>not as familiar with your app's innards (which could even be yourself, two
>>years hence) would not introduce such a problem?
>
>
> I don't care about that.

I beg your pardon. What little of the architecture you showed seemed
complex enough already to rule out the app being a one-off throwaway.

[...]

>>It is inherently unsafe to pass around pointers / references to partially
>>constructed objects, and Java intentionally makes it difficult (albeit not
>>impossible) to do so.
>
>
> And I, as a professional (and damned good) programmer know when
> I can safely use them. I don't need Gosling to protect me from
> myself.

I hear that Microsoft has a whole stable full of damned good
professional programmers, who have devoted thousands of man-years to a
product lineup that still manages to spring several newly discovered
bugs every week. This is not intended to slight those programmers (or
you); I am confident that the vast majority really are very good. And
even the best of them still make mistakes from time to time.

Whether you program in C++, Java, or some other language, it pays to
avoid not only recognized problems and failure scenarios, but also
potential problems and dangerous practices. The latter turn into many
of tomorrow's bugs -- and into many of today's when a very good
professional programmer makes a mistake.


John Bollinger
email***@***.com

 
 
Dale King





PostPosted: 2003-12-6 5:23:00 Top

java-programmer >> how to pass this before supertype constructor has been called "Paul J. Lucas" <email***@***.com> wrote in message
news:j2Kzb.65547$email***@***.com...
> John C. Bollinger <email***@***.com> wrote:
>
> > Java does not have pointers. It has references, which serve many of the
> > same roles, but no pointers.
>
> *eyeroll* On the machine-code level, which even Java must
> ultimaty run at, there are no references, only pointers. A
> reference is implemented as a pointer. How is it that you can
> get a "Null reference exception" then? It's really a null
> pointer just like in C++ or C, just with linguitsic sugar
> wrapped around it.
>
> > For example, there is no inherent logical inconsistency with any
particular
> > pointer referring any particular place in memory, but there _is_ a
logical
> > inconsistency with a reference whose referrent does not exist or has not
yet
> > been fully constructed.
>
> And, even if I grant you the above, for the case at hand, it's
> irrelevant, since (for something like the 6th time now): I'm not
> *using* the reference. I'm just storing it.
>
> > You are also missing Dale's point. He is describing a situation where
> > (a C++ implementation of) your design could potentially produce, hold,
> > and use rogue pointers.
>
> It can't use them unless I (the application programmer) access
> something through "this". As long as "this" is used only as a
> rvalue, everything is fine.
>
> > That would be a serious concern for program stability and perhaps even
system
> > security.
>
> Hogwash. Instability comes from inconsistent results based on
> unspecified behavior. There is no such thing (at least in C++)
> about using "this" *at* *any* *time* as an rvalue.
>
> > Perhaps it would never happen in your particular app -- I don't know, as
you
> > have only provided a schematic description.
>
> If I say (for the 7th time now) that I only store a copy of
> "this", then that's all the information that's needed.
>
> > But even if not, who's to say that some future modification by a
developer
> > not as familiar with your app's innards (which could even be yourself,
two
> > years hence) would not introduce such a problem?
>
> I don't care about that.
>
> > After analyzing my example of the problem (one branch to your left in
this
> > thread) and thinking about how the JVM works, my conclusion is that the
worst
> > that can happen on the Java side is that you end up with a reference to
an
> > object whose initialization was aborted midway.
>
> That's nice, but, again, irrelevant because "this" was never
> going to be used during a successful construction and obviously
> not during an unsuccessful one.
>
> > Its state may not be consistent, however, and use of the thing will not
> > be likely to reliably produce the expected results.
>
> There you go again: THERE IS NO "use of the thing." IT'S NOT
> USED IN THE CONSTRUCTOR, DAMMIT! Why is that so freaking hard
> for you to understand?

It doesn't matter that you *don't* use it. The point is that there is
nothing preventing you from using it. In other words it is OK to give you
the access codes to launch the nukes as long as you don't use them.

By passing the reference to another piece of code you are telling that piece
of code that the object that the reference refers to really is this type of
object. In your C++ code you are lying. You give a reference to something
that really isn't that type of object and any reliance on it being that type
of object will likely fail. Later on the fact the object will become what
you said it was. To me the fact that the other code doesn't currently rely
on the object to be what you said it was does not make the practice safe.
Code changes and that may not be true years from now when some maintenance
programmer changes the code.

> > Whether or not it is a paradox, it _is_ a problem in your design, both
> > in Java and in C++.
>
> No it isn't. It's perfectly legal and stable in C++.

So what. You are relying on a quirck of one particular language and
complaining that other languages do not also have that quirck. Your design
is not portable.

C++ also lets me do all sorts of unsafe things like casting pointers to
whatever I want them to be. That doesn't mean other languages are obliged to
follow suit.

> > It is inherently unsafe to pass around pointers / references to
partially
> > constructed objects, and Java intentionally makes it difficult (albeit
not
> > impossible) to do so.
>
> And I, as a professional (and damned good) programmer know when
> I can safely use them.

In other words you know when it is safe to lie.

> I don't need Gosling to protect me from
> myself.

Well, we do want someone protecting us from you then, if you think it is OK
to pass around references to uninitialized objects.

I tried the equivalent code in VC++, by the way and it doesn't give an
error, but does give a warning. So even in the C++ community the practice
seems to be frowned upon. I also assume that you will have the same
difficulty when trying to port to C#.