how to pass this before supertype constructor has been called

C

Chris Smith

Paul said:
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
 
D

Dale King

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

John C. Bollinger

Paul said:
Nothing at all.

Presumably this is either a hope, a specification, or an assumption. It
is not, however, the actual result.
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 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
(e-mail address removed)
 
P

Paul J. Lucas

John C. Bollinger said:
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
 
P

Paul J. Lucas

Chris Smith said:
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
 
P

Paul J. Lucas

Dale King said:
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
 
J

John C. Bollinger

Paul said:
[...]
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
(e-mail address removed)
 
J

John C. Bollinger

Paul said:
*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.
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.
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.

[...]
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
(e-mail address removed)
 
D

Dale King

Paul J. Lucas said:
*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.


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.


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.


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.


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.


I don't care about that.


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.


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

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

Forum statistics

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

Latest Threads

Top