Virtual function call from constructor

J

Jeff Higgins

This prints AB?

public class Test
{
Test()
{
foo();
}

static void foo()
{
System.out.print("A");
}

public static void main(String[] args)
{
Test t = new Test2();
}

static class Test2 extends Test
{
Test2()
{
super();
foo();
}

static void foo()
{
System.out.print("B");
}
}
}
 
E

Eric Sosman

Daniel said:
Hi all,

I came across some unexpected behaviour in Java: When I call a
member-function from a class' constructor, this call is done virtual as
usual calling the overridden method of the subclass.

This seems to me a bit problematic, as it calls a member-function of the
subclass which is not yet constructed and might therefore be well in an
inconsistent state. One can even call an abstract function from a
class' constructor.

... which is why every Java text warns you: "Don't Do That."
In C++, this is the other way round, there a constructor never calls an
overridden method from a subclass, so this inconsitent state can never
occur, which seems to me to be the better way. Calling a pure virtual
function from a constructor yields at least a warning and of course a
linker-error later on.

Is there any rationale behind this as it is done in Java? The only
reason I can think of is to handle function call's in constructors the
same way as it is done with ordinary calls. But the function to call
there is would be known at compile-time, so it shouldn't be really hard
to implement C++'s behaviour.

Suppose the class has a non-overridable method (private, final,
or static) that performs some useful operation on an object. And
suppose this method uses overridable methods of the object. Do
you need to compile two variants of this method to make it behave
differently depending on whether there is or isn't a constructor
somewhere in its call stack? (In fact, "a constructor" isn't
enough, not even "a constructor of the same class." If I've got
a fully-constructed object A lying around and I call a method on
it while constructing another object B, I want that method to obey
the overrides when applied to object A but not to B. I'm not sure
it's even possible to sort that out entirely at compile time. I
think you'd need a "construction finished" flag on every object --
in fact, one such flag for every level of inheritance starting
from Object itself. "Don't Do That" seems a lot simpler ...)
 
E

Eric Sosman

Daniel said:
Hm, that's a good point! I believe in C++ this is done by updating the
vtable for each constructor finished or something like this -- that
should also be fairly simple to implement and you do not need a
"construction finished" flag, but of couse it imposes some costs.

I don't know how C++ is implemented, but if the "vtable"
is a bunch of pointers to methods it sounds like you'd need a
per-instance edition of it to reflect the instance's fully-
or partially-constructed state. Sounds like a lot of bloat ...
"Don't do it" is of course nice, but precisly it should mean "only call
private, final and static methods from a constructor and only if they
themselves obey this rule", right?

Right.
But in this case, wouldn't a compile-time waring be useful telling me
I'm calling an overridable method from my constructor or the like?

I suppose so, but I don't think the compiler would be able
to detect every path that could lead to a Don't Do That call.
Some of them might not originate in the constructor at all: for
example, the constructor might insert the half-baked object in
a collection where another thread could find it before the
constructor has finished its job.
 
D

Daniel Kraft

Hi all,

I came across some unexpected behaviour in Java: When I call a
member-function from a class' constructor, this call is done virtual as
usual calling the overridden method of the subclass.

This seems to me a bit problematic, as it calls a member-function of the
subclass which is not yet constructed and might therefore be well in an
inconsistent state. One can even call an abstract function from a
class' constructor.

In C++, this is the other way round, there a constructor never calls an
overridden method from a subclass, so this inconsitent state can never
occur, which seems to me to be the better way. Calling a pure virtual
function from a constructor yields at least a warning and of course a
linker-error later on.

Is there any rationale behind this as it is done in Java? The only
reason I can think of is to handle function call's in constructors the
same way as it is done with ordinary calls. But the function to call
there is would be known at compile-time, so it shouldn't be really hard
to implement C++'s behaviour.

Or is this even considered "a feature"? However, I believe a function
should *never* be called on an unconstructed object except in the
constructor of the class itself where the programmer must take care this
call is valid there.

Cheers,
Daniel

******************************
Test.java

public class Test
{

public Test()
{
foo();
}

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

public static void main(String[] args)
{
Test t=new Test2();
}

public static class Test2 extends Test
{

public Test2()
{
super();
foo();
}

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

}

}

This produces:
B
B

********************************
Test.cpp

#include <iostream>
using namespace std;

class Test
{
public:
Test()
{
foo();
}
virtual void foo()
{
cout << "A" << endl;
}
};

class Test2 : public Test
{
public:
Test2()
: Test()
{
foo();
}
virtual void foo()
{
cout << "B" << endl;
}
};

int main()
{
Test* t(new Test2());
delete t;
return 0;
}

This produces:
A
B
 
D

Daniel Kraft

Jeff said:
This prints AB?

Try it out, for me it does.
public class Test
{
Test()
{
foo();
}

static void foo()
{
System.out.print("A");
}

public static void main(String[] args)
{
Test t = new Test2();
}

static class Test2 extends Test
{
Test2()
{
super();
foo();
}

static void foo()
{
System.out.print("B");
}
}
}
 
R

Roedy Green

This seems to me a bit problematic, as it calls a member-function of the
subclass which is not yet constructed and might therefore be well in an
inconsistent state. One can even call an abstract function from a
class' constructor.

You can get uninitialised variables and other weirdness. Generally
don't do it. Avoid calling virtual functions in constructors.

see http://mindprod.com/jgloss/constructor.html point #10.
 
D

Daniel Kraft

Suppose the class has a non-overridable method (private, final,
or static) that performs some useful operation on an object. And
suppose this method uses overridable methods of the object. Do
you need to compile two variants of this method to make it behave
differently depending on whether there is or isn't a constructor
somewhere in its call stack? (In fact, "a constructor" isn't
enough, not even "a constructor of the same class." If I've got
a fully-constructed object A lying around and I call a method on
it while constructing another object B, I want that method to obey
the overrides when applied to object A but not to B. I'm not sure
it's even possible to sort that out entirely at compile time. I
think you'd need a "construction finished" flag on every object --
in fact, one such flag for every level of inheritance starting
from Object itself. "Don't Do That" seems a lot simpler ...)

Hm, that's a good point! I believe in C++ this is done by updating the
vtable for each constructor finished or something like this -- that
should also be fairly simple to implement and you do not need a
"construction finished" flag, but of couse it imposes some costs.

"Don't do it" is of course nice, but precisly it should mean "only call
private, final and static methods from a constructor and only if they
themselves obey this rule", right?

But in this case, wouldn't a compile-time waring be useful telling me
I'm calling an overridable method from my constructor or the like?

Yours,
Daniel
 
L

Lew

Daniel said:
Right, the vtable (or virtual table) is a table of function pointers
stored within each object so the overridden method is found. But I
really believe this is there in Java, too, but in Java of course the
fact of methods being virtual is "hidden" to the programmer.

So yes, this is some bloat, but AFAIK this bloat is really necessary for
polymorphism with virtual methods. And unlike Java, in C++ you do not
have to keep a pointer there for *every* method a class has, only to
those which you really intend to be overridden and used polymorphistic...

So don't use Java, then. Do your work in C++.

What do you mean by "you ... have to keep a pointer"? Are you certain that
Java doesn't inline non-polymorphic methods, or even polymorphic ones? How is
"keeping a pointer" less worthy than not doing so? In any event, vtable or
not, threaded or pointer, has literally nothing to do with Java semantics,
which are defined irrespective of their implementation.

It seems to me that the illogic of a method only being polymorphic outside a
constructor but, inconsistently, not inside it, trumps the apparent illogic
but actual good sense of polymorphic (or otherwise) methods only seeing
fully-constructed objects after they're fully constructed.
 
D

Daniel Kraft

Eric said:
I don't know how C++ is implemented, but if the "vtable"
is a bunch of pointers to methods it sounds like you'd need a
per-instance edition of it to reflect the instance's fully-
or partially-constructed state. Sounds like a lot of bloat ...

Right, the vtable (or virtual table) is a table of function pointers
stored within each object so the overridden method is found. But I
really believe this is there in Java, too, but in Java of course the
fact of methods being virtual is "hidden" to the programmer.

So yes, this is some bloat, but AFAIK this bloat is really necessary for
polymorphism with virtual methods. And unlike Java, in C++ you do not
have to keep a pointer there for *every* method a class has, only to
those which you really intend to be overridden and used polymorphistic...

Cheers,
Daniel
 
M

Mike Schilling

You are correct.
I don't know how C++ is implemented, but if the "vtable"
is a bunch of pointers to methods it sounds like you'd need a
per-instance edition of it to reflect the instance's fully-
or partially-constructed state. Sounds like a lot of bloat ...

Not per-instance, per-class. Assume S2 extends S1, and S1 extends S0. An
Sn constructor:

calls the superclass constructor (if there is a superclass)
points its vtable at the Sn version
runs its code

The result is that the constructor runs as if the object were the type being
constructed, and when all have run, the object is of the correct
(most-derived) type. No bloat involved. I always find it silly when people
who know nothing about a language assume that if it does things differently
from the languages they're used to, it must be stupid and inefficient to do
so.

Calling virtual methods (directly or indirectly) in a constructor is
problematical. C++ tries to solve it by limiting the way they're called.
Java makes avoiding problems wholly the programmer's responsibility.
Neither is stupid or inefficient; both have advantages and disadvantages.
(Ironically, the difference is opposite to the usual one, since C++ is being
nannyish and Java is giving you all the rope you want.)
 
M

Mike Schilling

....
Right, the vtable (or virtual table) is a table of function pointers
stored within each object so the overridden method is found. But I really
believe this is there in Java, too, but in Java of course the fact of
methods being virtual is "hidden" to the programmer.

Not at all. In Java, private methods aren't virtual and all other methods
are, and this is understood by every competent Java programmer. And the
vtable in C++ is part of the implementation: it's not something the
programmer can access [1], and thus is equally "hidden".
So yes, this is some bloat,

No, there isn't. See my explanation upthread.
but AFAIK this bloat is really necessary for polymorphism with virtual
methods. And unlike Java, in C++ you do not have to keep a pointer there
for *every* method a class has, only to those which you really intend to be
overridden and used polymorphistic..

The inner workings of the JVM are very hidden. There's no reason to think
that if a method is never overridden that the JVM can't dispatch to a
method directly.

1. OK, you can access it using casts and pointer arithmetic, in an
implementation-specific way. I've done this, and even for good reasons.
But it's not part of the language definition.
 
T

Twisted

"Don't do it" is of course nice, but precisly it should mean "only call
private, final and static methods from a constructor and only if they
themselves obey this rule", right?

Basically. I'd divide my methods into "those that can definitely cope
with an incompletely-constructed Foo" and "all the others". The latter
including all methods not in Foo, including in Foo's superclass but
not overridden by Foo, or overridable by Foo's subclasses. So the
first set is already limited to a subset of the final, static, and
private methods of Foo. Lastly, the rule I'd have is for the
constructor *never to pass "this" to a method not in the first
subset*, and to exclude a method from that subset if it ever passes
"this" to a method outside the subset.

This includes the implicit "this" argument passed when invoking a
member, of course.

The rule that results is "only call private, final and static methods
from a constructor and only if they themselves obey this rule" with
the additional restriction that this additionally applies to methods
of ANY class receiving an explicit argument of "this".

In fact, javac complains in some cases about passing "this" as an
argument to a method call from a constructor, which helps avoid some
bad potential problems.
 
E

Eric Sosman

Mike said:
You are correct.

Not per-instance, per-class. Assume S2 extends S1, and S1 extends S0. An
Sn constructor:

calls the superclass constructor (if there is a superclass)
points its vtable at the Sn version
runs its code

The result is that the constructor runs as if the object were the type being
constructed, and when all have run, the object is of the correct
(most-derived) type. No bloat involved. I always find it silly when people
who know nothing about a language assume that if it does things differently
from the languages they're used to, it must be stupid and inefficient to do
so.

Somehow I'm failing to find the word "stupid" or "inefficient"
in anything that I wrote. Could you help me with my proofreading,
please?

I *did* use the word "bloat," and it still seems justifiable.
The implementation you describe (if I've understood you correctly)
requires each instance to carry a pointer per inheritance level;
that's certainly larger than the one bit per level I described as
a hypothetical implementation, and that in turn is larger than
no per-instance "construction status" at all.
 
M

Mike Schilling

I *did* use the word "bloat," and it still seems justifiable.
The implementation you describe (if I've understood you correctly)
requires each instance to carry a pointer per inheritance level;
that's certainly larger than the one bit per level I described as
a hypothetical implementation, and that in turn is larger than
no per-instance "construction status" at all.

Not at all. It requires each instance to hold one pointer, period. The
*value* of this pointer is changed during construction.
 
E

Eric Sosman

Mike said:
Not at all. It requires each instance to hold one pointer, period. The
*value* of this pointer is changed during construction.

Aha! So if you've got a class that's N levels deep in the
inheritance hierarchy, you've got N+1 versions of the vtable,
each corresponding to a different amount of progress through
the constructor chain. Is that it?

Hmmm... If that's the way it works, then defining an Nth
level class really defines N+1 distinct classes, in the sense
that a class is the set of its behaviors. If applied to an
object in the midst of construction, which of those N+1 classes
should getClass() return? And how should instanceof behave?
 
M

Mike Schilling

Eric Sosman said:
Aha! So if you've got a class that's N levels deep in the
inheritance hierarchy, you've got N+1 versions of the vtable,
each corresponding to a different amount of progress through
the constructor chain. Is that it?

Each class that contains virtual functions defines a vtable. Each instance
of one of these classes contains one pointer, which points to its class's
vtable. So an instance of String points to String's vtable, an instance of
Thread points to Thread's vtable,etc. So far, just as you'd expect. If you
replace "vtable" by "Class object" and observe that all Java classes contain
virtual functions (the ones they inherit from Object, at least), exactly
like Java.

What C++ does differently is this: During construction, the value of that
vtable pointer can changes. It will always point to the vtable for the
class that defines the constructor. So (to use a Java-like example, for
familiarity), when a PrintStream is being constructed, it does something
,like this:

Point to Object vtable
Run Object constructor
Point to OutputStream vtable
Run OutputStream constructor
Point to FilterOutputStream vtable
Run FilterOutputStream constructor
Point to PrintStream vtable
Run PrintStream constructor

At the end of this, the vtable is (correctly) left pointing to the
PrintStream vtable, which it keeps for the rest of its left. It's possible
that the reverse process happens during destruction, but I can't say for
sure. If so, it would be nicely symmetrical.

Hmmm... If that's the way it works, then defining an Nth
level class really defines N+1 distinct classes, in the sense
that a class is the set of its behaviors.

Not really, because the superclasses already exist. You're defining only
one new class.
If applied to an
object in the midst of construction, which of those N+1 classes
should getClass() return? And how should instanceof behave?

C++ doesn't have either of those per se. It does have some limited
reflection, for instance the <dynamic_cast> operator, which does a similar
job to instanceof, which I presume would base the current type of the
object on the current vtable, so that, in effect,

x instanceof PrintStream

would be false during the running of the FilterOutputStream constructor.
Which makes a certain amount of sense: none of the PrintStream fields have
been initialized, nor are PrintStream-specific methods available.

Think of it this way. When the Object constructor is running, the instance
*is* an Object. It may have some extra space allocated at the end, but no
one can make any use of it. Now, when the OutputStream constructor is
running, the instance *is* an OutputStream. It may have some extra space
allocated at the end, but no one can make any use of it. etc. Finally, when
the PrintStream constructor runs, it *is* a PrintStream.
 
T

Twisted

What C++ does differently is this: During construction, the value of that
vtable pointer can changes. It will always point to the vtable for the
class that defines the constructor.

Think of it this way: while a Java object is whatever run-time type it
is for its whole lifetime, a C++ object actually evolves; its run-time
type is Base during the Base constructor, then Derived when the
Derived constructor is running. Its run-time type is whatever is fully-
constructed so far.
Not really, because the superclasses already exist. You're defining only
one new class.

For example with Base and Derived, there may be a trivial vtable and
there will be ones for Base and Derived. But the one for Base is used
not only for incomplete Deriveds, but for other subclasses and vanilla
Bases as well.
C++ doesn't have either of those per se. It does have some limited
reflection, for instance the <dynamic_cast> operator, which does a similar
job to instanceof...

Actually, it does the exact same job as a Java cast as in "(String)
myMap.get(key)" (a common case, pre-Java 5). It gives you a reference
of the desired compile-time type if the run-time type is assignable to
that compile-type type, and throws an exception if it isn't so
assignable. In Java the exception is a ClassCastException; in C++ it's
something else (bad_cast?) (C++ also has bad_alloc, analogous to
OutOfMemoryError, and some other exceptions that closely map onto Java
ones.)
which I presume would base the current type of the
object on the current vtable, so that, in effect,

x instanceof PrintStream

would be false during the running of the FilterOutputStream constructor.
Which makes a certain amount of sense: none of the PrintStream fields have
been initialized, nor are PrintStream-specific methods available.

I think there may be an RTTI (run-time type identification) ability
more like instanceof than dynamic_cast; I'm not sure if it treats
objects' run-time types as evolving during construction, though it
seems likely. Dynamic dispatch certainly does, regardless.
Think of it this way. When the Object constructor is running, the instance
*is* an Object. It may have some extra space allocated at the end, but no
one can make any use of it. Now, when the OutputStream constructor is
running, the instance *is* an OutputStream. It may have some extra space
allocated at the end, but no one can make any use of it. etc. Finally, when
the PrintStream constructor runs, it *is* a PrintStream.

Except that in Java it's a PrintStream from the outset, and is not a
vanilla Object even when Object's constructor is not finished yet.
(Does Object even have a nontrivial constructor?) This only applies to
their C++ analogues in the iostreams library. :)
 
M

Mike Schilling

Except that in Java it's a PrintStream from the outset, and is not a
vanilla Object even when Object's constructor is not finished yet.
(Does Object even have a nontrivial constructor?)

That's presumably a JVM-specific question.
This only applies to
their C++ analogues in the iostreams library. :)

Yes, I was probably unclear. I was trying to describe the C++ mechanism,
but using a Java class hierarchy as an example (since there wasn't a C++
hierarchy handy.)
 
T

Twisted

That's presumably a JVM-specific question.

Yes. I expect a JVM and a corresponding implementation of at least the
java.lang portion of the standard library to be fairly tightly
coupled; probably why they are bundled and transported about as a
single entity, a JRE. Certainly some System stuff, Object.wait/notify,
and the stuff in java.lang.ref will be tightly coupled to the VM
implementation in various ways, and likely also String interning.
Class/ClassLoader and reflection too, and now probably
java.util.concurrency (and that one doesn't even start with
java.lang).
Yes, I was probably unclear. I was trying to describe the C++ mechanism,
but using a Java class hierarchy as an example (since there wasn't a C++
hierarchy handy.)

I figured as much, but also figured it might not be clear to every
reader. Having similar stuff expressed in other words as well will
probably make it much more reliably understood by this thread's
readers.
 
E

Eric Sosman

Mike said:
That's presumably a JVM-specific question.

No; that's the Java language. If Object's constructor
ultimately chained from a PrintStream constructor were to
evaluate `this instanceof PrintStream' the result would be
`true', on every JVM. (Object's constructor has no reason
to do any such thing, but that's another matter.)

You can test the pattern with

class Super {
Super() {
System.out.println((this instanceof Super)
+ ", " + (this instanceof Sub));
}
public static void main(String[] unused) {
new Super();
new Sub();
}
}
class Sub extends Super {
}
 

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,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top