Call virtual function in constructor

J

junw2000

Is there any problem if call virtual function in constructor? For
example:

class A
{
public:
A()
{
setvalue();
}

setvalue()
{
data = getnumber();
}

print() { cout << data << endl;

private:
virtual int getnumber() {return 100;}
int data;
}

class B : public A
{
public:
B() { }

private:
virtual int getnumber() {return 22222;}

}

int main()
{
A test1;
test1.print() ;

B test2;
test2.print() ;

}

Thanks.

Jack
 
R

red floyd

Is there any problem if call virtual function in constructor? For
example:

class A
{
public:
A()
{
setvalue();
}

setvalue()
{
data = getnumber();
}

print() { cout << data << endl;

private:
virtual int getnumber() {return 100;}
int data;
}

class B : public A
{
public:
B() { }

private:
virtual int getnumber() {return 22222;}

}

int main()
{
A test1;
test1.print() ;

B test2;
test2.print() ;

}

Thanks.

Yes, there's a problem. When you construct a B, at the time the virtual
function is called from A's constructor, the B hasn't been constructed
yet, so you get either A's version or undefined behavior (I can't
remember which, and my copy of the Standard is at work).
 
I

Ian Collins

Is there any problem if call virtual function in constructor?

Yes, you simply should no do it. Derived classes haven't been
constructed when the base class constructor is called. Try making the
function pure in the base class and see what happens...
 
P

peter koch

Is there any problem if call virtual function in constructor? For
example:

class A
{
public:
     A()
     {
           setvalue();
     }

    setvalue()
    {
           data = getnumber();
    }

    print() { cout << data << endl;

private:
    virtual int getnumber() {return 100;}
    int data;

}

class B : public A
{
public:
         B() { }

private:
         virtual int getnumber() {return 22222;}

}

int main()
{
     A test1;
     test1.print() ;

     B test2;
     test2.print() ;

}

Thanks.

In this case the call is alright, and data will obtain the value of
1000. But beware! This might not be what you guessed would happen, and
if you so might not be what your collegues believe. So my advice (if
you insist on having the function virtual as in your test which is not
a really good solution) is to keep a comment to explain what takes
place.
Why behaviour is as it is? Because there is no B object when A's
constructor runs: it has not been constructed yet.

/Peter
 
P

Pavel

Is there any problem if call virtual function in constructor? For
example:

class A
{
public:
A()
{
setvalue();
}

setvalue()
{
data = getnumber();
}

print() { cout << data << endl;

private:
virtual int getnumber() {return 100;}
int data;
}

class B : public A
{
public:
B() { }

private:
virtual int getnumber() {return 22222;}

}

int main()
{
A test1;
test1.print() ;

B test2;
test2.print() ;

}

Thanks.

Jack

2 more cents: because 100 is all the code can realistically hope to get
in the constructor, the following functionally equivalent code for A can
make its intention clear without extra comments:

class A
{
public:
A() { data = getNumberOfA(); }
void setvalue() { data = getnumber(); }
void print() { cout << data << endl; }
private:
virtual int getnumber() { return getNumberOfA(); }
int getNumberOfA() { return 100; }
int data;
};

Hope this will help
-Pavel
 
K

Kira Yamato

Is there any problem if call virtual function in constructor? For
example:

class A
{
public:
A()
{
setvalue();
}

setvalue()
{
data = getnumber();
}

print() { cout << data << endl;

private:
virtual int getnumber() {return 100;}
int data;
}

class B : public A
{
public:
B() { }

private:
virtual int getnumber() {return 22222;}

}

int main()
{
A test1;
test1.print() ;

B test2;
test2.print() ;

}

Technically, it's perfectly fine to call virtual functions in the
constructor as long as you understand that it will not invoke any
possible derived-class's overriding version of the same method. Also,
your compiler will complain if you're calling a pure virtual function.

However, semantically speaking, it seems weird why you would want to
invoke a method that your object wishes to override. I can't pinpoint
it yet, but it seems like a bad design. Sorry for being so vague.
Perhaps an expert can help point out the problem in a clear way.
 
P

Pavel

Kira said:
Technically, it's perfectly fine to call virtual functions in the
constructor as long as you understand that it will not invoke any
possible derived-class's overriding version of the same method. Also,
your compiler will complain if you're calling a pure virtual function.

However, semantically speaking, it seems weird why you would want to
invoke a method that your object wishes to override. I can't pinpoint
it yet, but it seems like a bad design. Sorry for being so vague.
Perhaps an expert can help point out the problem in a clear way.

It is sometimes useful to initialize different classes of a hierarchy
with the derived class-dependent code and then return back to the base
class constructor to execute some of its code again to avoid duplicating
that latter common code.

For example (this code will not work in C++ but the analogous code will
work in other programming languages (e.g. Java) and I do not see any
fundamental design flaws in this code).:

typedef std::map<std::string> ConnectionParameters;
class FooConnection {
protected:
virtual void init(const ConnectionParameters &pars) = 0;
public:
FooConnection(const ConnectionParameters &pars) {
init(pars);
validateConnection();
}
private:
void validateConnection()
throw(FooConnectionException /*defined elsewhere*/)
{
/* perform some uniform validation here, for example
some select from "FOO_MAIN_TABLE" */
}
};
class OracleFooConnection : public FooConnection {
protected:
void init(const ConnectionParameters &pars) {
// .. do Oracle-specific initialization
}
};
class MySqlFooConnection : public FooConnection {
protected:
void init(const ConnectionParameters & pars) {
// .. do MySql-specific initialization
}
};

This way, you can perform all validation in the constructor, that is,
according to the best practices, and without duplicating the common
validation code in the derived class.

It is a C++ - specific feature that the implementation is not required
to construct the memory layout for the whole object of the most derived
class before calling the first constructor of a base class (Java does it
differently).

Of course, there are ways in C++ to cure this limitation, for example by
composition, where you can create a parallel Impl hierarchy which does
not validate, use member access control and "friends" to make its object
accessible only from within the primary hierarchy classes, move
database-specific init() into the parallel hierarchy and leave the
validateConnection() in the main hierarchy's base class. Sometimes this
added design complexity will be not much of a burden, sometimes it will
be. Personally I would prefer to have a choice not to use it.

-Pavel
 
A

Alf P. Steinbach

* Pavel:
It is sometimes useful to initialize different classes of a hierarchy
with the derived class-dependent code and then return back to the base
class constructor to execute some of its code again to avoid duplicating
that latter common code.

For example (this code will not work in C++ but the analogous code will
work in other programming languages (e.g. Java) and I do not see any
fundamental design flaws in this code).:

typedef std::map<std::string> ConnectionParameters;
class FooConnection {
protected:
virtual void init(const ConnectionParameters &pars) = 0;
public:
FooConnection(const ConnectionParameters &pars) {
init(pars);
validateConnection();
}
private:
void validateConnection()
throw(FooConnectionException /*defined elsewhere*/)
{
/* perform some uniform validation here, for example
some select from "FOO_MAIN_TABLE" */
}
};
class OracleFooConnection : public FooConnection {
protected:
void init(const ConnectionParameters &pars) {
// .. do Oracle-specific initialization
}
};
class MySqlFooConnection : public FooConnection {
protected:
void init(const ConnectionParameters & pars) {
// .. do MySql-specific initialization
}
};

"not ... any fundamental design flaws": heh, it is reportedly the most
common source of Java bugs.

The problem is that at the time the derived class' function
implementation is called, the derived class object has not yet been
initialized. Thus, member functions called from that function, or even
that function's own implementation, may very easily execute code that
relies on assumptions that have not yet been established. Apart from
run-time checking of array downcasts, which is also a strong contender,
I think that this is the most ugly type system breach in Java.


This way, you can perform all validation in the constructor, that is,
according to the best practices, and without duplicating the common
validation code in the derived class.

The above code is (unfortunately) common practice in Java, but it's
certainly not best practice.

It's an example of the exact opposite.

It is an anti-pattern.

It is a C++ - specific feature that the implementation is not required
to construct the memory layout for the whole object of the most derived
class before calling the first constructor of a base class (Java does it
differently).

Of course, there are ways in C++ to cure this limitation, for example by
composition, where you can create a parallel Impl hierarchy which does
not validate, use member access control and "friends" to make its object
accessible only from within the primary hierarchy classes, move
database-specific init() into the parallel hierarchy and leave the
validateConnection() in the main hierarchy's base class. Sometimes this
added design complexity will be not much of a burden, sometimes it will
be. Personally I would prefer to have a choice not to use it.

For ways to achieve dynamic binding during initialization (DBDI) in C++,
which also are more sane ways in Java, see FAQ item 23.6.

I think of that as "my" FAQ item since I convinced Marshall to include
it, but the text and exposition is of course Marshall's.

Unfortunately this happened much later than the treatment of clone
functions, so we're stuck with the term "virtual construction", at least
in the FAQ, referring to cloning, and the acronym "DBDI" (Marshall's
invention) for the techniques discussed in 23.6.


Cheers, & hth.,

- Alf
 
K

Kira Yamato

It is sometimes useful to initialize different classes of a hierarchy
with the derived class-dependent code and then return back to the base
class constructor to execute some of its code again to avoid
duplicating that latter common code.

For example (this code will not work in C++ but the analogous code will
work in other programming languages (e.g. Java) and I do not see any
fundamental design flaws in this code).:

typedef std::map<std::string> ConnectionParameters;
class FooConnection {
protected:
virtual void init(const ConnectionParameters &pars) = 0;
public:
FooConnection(const ConnectionParameters &pars) {
init(pars);
validateConnection();
}
private:
void validateConnection()
throw(FooConnectionException /*defined elsewhere*/)
{
/* perform some uniform validation here, for example
some select from "FOO_MAIN_TABLE" */
}
};
class OracleFooConnection : public FooConnection {
protected:
void init(const ConnectionParameters &pars) {
// .. do Oracle-specific initialization
}
};
class MySqlFooConnection : public FooConnection {
protected:
void init(const ConnectionParameters & pars) {
// .. do MySql-specific initialization
}
};

This way, you can perform all validation in the constructor, that is,
according to the best practices, and without duplicating the common
validation code in the derived class.

Interesting example. However, I would like to propose that in any case
where the construction of an object is complicated enough, the factory
pattern should be considered.

In your example above, a FooConnectionFactory can be used to invoke the
derived-class-specific initiation code as well as
derived-class-specific validation code. This way avoids the need to
invoke derived-class overridden methods.
 
P

Pavel

Alf said:
* Pavel:

"not ... any fundamental design flaws": heh, it is reportedly the most
common source of Java bugs.

The problem is that at the time the derived class' function
implementation is called, the derived class object has not yet been
initialized. Thus, member functions called from that function, or even
that function's own implementation, may very easily execute code that
relies on assumptions that have not yet been established. Apart from
run-time checking of array downcasts, which is also a strong contender,
I think that this is the most ugly type system breach in Java.

Thanks Alf!

I totally agree the objects should not be operated on until completely
initialized.

However, in this particular case we are talking about the initialization
itself and how conveniently the initialization can be performed and
factored onto the most relevant pieces of code, rather than about
regular operations. It can hardly be argued that initialization is
supposed to operate on uninitialized objects.

I also agree that every powerful feature of any language can be abused.
Well, both C++ and Java provide a rich variety of ways to abuse them
(arguably, C++ provides more) and one more is not going to change the
weather.

The above code is (unfortunately) common practice in Java, but it's
certainly not best practice.
Well, I just said that keeping all validations in the constructor agrees
with the best practices because the client code then "never" has an
access to an invalid object.
It's an example of the exact opposite.

It is an anti-pattern.
I did not call the code above a pattern but "anti-pattern" seems little
"out of wack" to me :). Why don't we try to refrain from tagging or
rubber-stamping each other's examples?
For ways to achieve dynamic binding during initialization (DBDI) in C++,
which also are more sane ways in Java, see FAQ item 23.6.

I think of that as "my" FAQ item since I convinced Marshall to include
it, but the text and exposition is of course Marshall's.

Unfortunately this happened much later than the treatment of clone
functions, so we're stuck with the term "virtual construction", at least
in the FAQ, referring to cloning, and the acronym "DBDI" (Marshall's
invention) for the techniques discussed in 23.6.

Well, I have read that FAQ entry carefully and I cannot agree it
suggests a clearly better solution to the original problem for which I
suggested that virtual calls in constructor would be useful. I stated
the problem in words in the beginning of my previous post, but for more
clarity let me illustrate it with a little client code snippet here.
Imagine that

#include <foo.h>

int main(int argc, char *argv[]) {
ConnectionParameters params(argv[1]);
/* this time, please assume that ConnectionParameters can be built from
a string argv[1] or a text file with this name -- seems reasonable */
OracleFooConnection fooConnection(params);
fooConnection.doSomethingUseful();
return 0;
}

is all our client is willing to write in his/her code. Fair and square.
His/her business requirements are this simple and if a programming
language does not allow similar level of simplicity in the solution, it
will not be chosen (and neither will be our Foo library we happened to
write in that programming language and needless to say we will not have
luxury of programming in that language much longer no matter how badly
we love that language). With the requirements in mind, the first
approach, first "joe_user" function does not work. Also, it would be
less safe than my code above because, my init() function is protected
and it takes some creativity from the client to call it incidentally
(which is the only way to "access non-initialized object" even though
there is nothing wrong in calling init() on uninitialized object) and
the FAQ's init() is public and open for any misuse (calling at the wrong
time or being forgotten at all which is worse in our case).

The second variation of the first FAQ approach could be a little better
but it leaves out too many details (most notably, how to initialize the
factory and why would Base class have all necessary parameters for this
without a client code cooperation and how bulky such cooperation could
be). In fact, it does not give any example of the client code
("joe_func()" or whatever). It also assumes that the Base class knows
how to process *all* information needed to create the object of *any*
derived class (in terms of the parameter types) and this may easily lead
to bad hacking in the future when a new type of FooConnection comes
(say, LdapOracleFooConnection that will take a handle to LDAP connection
as a parameter instead of ConnectionParameters. Then, the
LdapOracleFooConnection class's constructor could build the
ConnectionParameters object required by the FooConnection's constructor
but with the FAQ's first approach, second variation it cannot be done
because the parameters of the Base constructor cannot hold the
connection handle).

The second approach (a second class hierarchy) is essentially similar to
what I suggest in my post as a "cure" for the limitation) with the
difference that I would hide the helper objects inside the primary
objects -- maybe matter of taste but seems more straightforward to me
than the "magic" constructor parameters. As I said, in some situations
the added complexity of the implementation can be justified. Way too
often, however, the inability to *easily* structure the initialization
code in the most rational way will lead to pretty ugly design
compromises. Some developers, even quite experienced once, who would
come to term with a single class hierarchy, under time pressure will
create a do-it-all FooConnection class, which will remember whether it
is Oracle or MySql (with all pleasantries of the correspondent state
management) instead of managing two parallel hierarchies. In a different
situation, when the parallel hierarchy approach is implemented
correctly, a new-to-the-project developer who is tasked to add a new
BarFooConnection will still have some nice time understanding what
exactly s/he should do and why the single responsibility (construction,
in our case) must be scattered across 2 classes.

I do not want even discuss the second approach, stateless case because
it is not applicable to my problem (which requires the connection state)
and even if it were, I would feel conscious leaving this mini-framework
to my fellow developer to maintain and re-use. Function pointers in
constructor parameters would make him/her suspect I was doing something
terribly smart, solving some rocket-science problem of a very dynamic
nature -- which I was not, I was just trying to reasonably factor my
initialization code.

Again, I am not trying to say the parallel hierarchies are *always
unconditionally worse* than virtual calls in constructors would be. My
humble point is that it is at least arguable that the benefits of
"disabling" (quoting because of the possibility of casting) one
relatively rarely met language abuse (yes, even in Java it does not
happen often, it is just that Java crowd is on average younger and likes
to make big noise of every wheel they re-invent and every old snag they
hit) outweigh the drawbacks of alternative solutions suggested by your
FAQ entry or by me.

I allow there could be better alternative solutions (than both in your
FAQ entry and the one I would use) but the very fact we do not know
about them immediately is a good indication that the language feature we
discuss may have an issue. This said, I would certainly like to hear
about such a better solution.
Cheers, & hth.,

- Alf

Regards,
-Pavel
 
P

Pavel

Kira said:
It is sometimes useful to initialize different classes of a hierarchy
with the derived class-dependent code and then return back to the base
class constructor to execute some of its code again to avoid
duplicating that latter common code.

For example (this code will not work in C++ but the analogous code
will work in other programming languages (e.g. Java) and I do not see
any fundamental design flaws in this code).:

typedef std::map<std::string> ConnectionParameters;
class FooConnection {
protected:
virtual void init(const ConnectionParameters &pars) = 0;
public:
FooConnection(const ConnectionParameters &pars) {
init(pars);
validateConnection();
}
private:
void validateConnection()
throw(FooConnectionException /*defined elsewhere*/)
{
/* perform some uniform validation here, for example
some select from "FOO_MAIN_TABLE" */
}
};
class OracleFooConnection : public FooConnection {
protected:
void init(const ConnectionParameters &pars) {
// .. do Oracle-specific initialization
}
};
class MySqlFooConnection : public FooConnection {
protected:
void init(const ConnectionParameters & pars) {
// .. do MySql-specific initialization
}
};

This way, you can perform all validation in the constructor, that is,
according to the best practices, and without duplicating the common
validation code in the derived class.

Interesting example. However, I would like to propose that in any case
where the construction of an object is complicated enough, the factory
pattern should be considered.

In your example above, a FooConnectionFactory can be used to invoke the
derived-class-specific initiation code as well as derived-class-specific
validation code. This way avoids the need to invoke derived-class
overridden methods.
Thanks Kira,

Yes this is another working solution, a nice compromise that adds less
extra *implementation* complexity than parallel class hierarchies. It
instead adds some complexity almost evenly to the interface (the client
has to use a Factory whereas s/he does not necessarily want or have to
deal with any other class than the contcrete class OracleFooConnection;
also, s/he might need to think about destruction, e.g. use auto_ptr or a
similar facility that could be avoided with a simple-object-on-the-stack
solution). One more little potential drawback is pointed out in my
answer to Alf's in LdapOracleFooConnection class example -- a limitation
on the future extensibility of the hierarchy.

Of course the benefits of the Factory solution can be plenty, too --
depending on the particular situation. All I am saying I would prefer to
have a choice whether to invoke or not the derived class's overriden
method (wasn't it the C++ promise, after all, that I must be able to
blow off my whole leg if I try hard enough?).

-Pavel
 
A

Alf P. Steinbach

* Pavel:
Thanks Alf!

I totally agree the objects should not be operated on until completely
initialized.

However, in this particular case we are talking about the initialization
itself and how conveniently the initialization can be performed and
factored onto the most relevant pieces of code, rather than about
regular operations. It can hardly be argued that initialization is
supposed to operate on uninitialized objects.

I think you meant to write "It can hardly be argued that initialization
is only supposed to operate on initialized objects".

That is true.

In C++ this is dealt with by constructors, which, as opposed to other
member functions, operate on not-yet-initialized objects.

The problem with Java's virtual calls from constructors can be restated
in these terms, that that mechanism does not deal with that problem.

Specifically, that it causes member functions other than constructors to
operate on not-yet-initialized objects (or more precisely, for Java, on
objects that have not yet had their class invariants established).

I also agree that every powerful feature of any language can be abused.
Well, both C++ and Java provide a rich variety of ways to abuse them
(arguably, C++ provides more) and one more is not going to change the
weather.


Well, I just said that keeping all validations in the constructor agrees
with the best practices because the client code then "never" has an
access to an invalid object.

Well, nothing wrong with what you state here as follow-up.

What's wrong is the earlier "This way...", the virtual call (in Java and
some other languages) in the constructor invoking a function
implementation in a derived class.

That is not necessary in order to keep all validation in the
constructor, nor is it necessary in order to ensure that client code
only has access to valid objects.

I did not call the code above a pattern but "anti-pattern" seems little
"out of wack" to me :). Why don't we try to refrain from tagging or
rubber-stamping each other's examples?

The above was a precise (well, OK, not that precise!) technical description.

Coming from rural Northern Norway, you know, fishermen and such, I can
assure you that when I resort to name calling, you'll know it... :).

See <url: http://en.wikipedia.org/wiki/Anti-pattern> for a general
introduction to antipatterns.

Doing a Google search for a name of this particular antipattern didn't
turn up any hits.

However, since it is an antipattern it's called an antipattern here &
there on the net, e.g. <url:
http://mehranikoo.net/CS/archive/2006/11/28/InstanceConstructors.aspx>
and <url: http://debasishg.blogspot.com/2006_11_01_archive.html> (which
indicates the Eclipse can detect this antipattern automatically).

For ways to achieve dynamic binding during initialization (DBDI) in
C++, which also are more sane ways in Java, see FAQ item 23.6.

I think of that as "my" FAQ item since I convinced Marshall to include
it, but the text and exposition is of course Marshall's.

Unfortunately this happened much later than the treatment of clone
functions, so we're stuck with the term "virtual construction", at
least in the FAQ, referring to cloning, and the acronym "DBDI"
(Marshall's invention) for the techniques discussed in 23.6.

Well, I have read that FAQ entry carefully and I cannot agree it
suggests a clearly better solution to the original problem for which I
suggested that virtual calls in constructor would be useful. I stated
the problem in words in the beginning of my previous post, but for more
clarity let me illustrate it with a little client code snippet here.
Imagine that

#include <foo.h>

int main(int argc, char *argv[]) {
ConnectionParameters params(argv[1]);
/* this time, please assume that ConnectionParameters can be built from
a string argv[1] or a text file with this name -- seems reasonable */
OracleFooConnection fooConnection(params);
fooConnection.doSomethingUseful();
return 0;
}

is all our client is willing to write in his/her code. Fair and square.

Perhaps you may find my original sketch for that item more clear, <url:
http://home.no.net/alfps/cpp/faq_proposal/@virtual-functions.html#faq-20.7>,
although now I'm not sure what I meant at the end of the previous item
on that page (it was possibly some old VC6 problem) -- if I'd read
that written by someone else I'd probably used some very choice words...

For your particular case I'd choose what I in the page above call a
"part-creator", directly supporting the client code you show above.

It would go like (off the cuff)

class ConnectionFactory
{
public:
typedef ... Handle;
typedef ... Params;

Handle create( Params& const params ) const
{
Handle const h = doCreate( params );

isValid( h ) || throwX( "Burka!" );
return h;
}

virtual bool isValid( Handle const& h ) const = 0;

private:
virtual Handle doCreate( Params const& ) const = 0;
};


class FooConnection
{
public:
typedef ConnectionFactory::Handle Handle;
typedef ConnectionFactory::params Params;

protected:
FooConnection(
Params const& params,
ConnectionFactory const& factory // Might default
)
: myHandleOnThings( factory.create( params ) )
{}

private:
Handle myHandleOnThings;
};


class OracleFooConnection : public FooConnection
{
public:
OracleFooConnection( Params const& params )
: FooConnection( params, Factory() )
{}

private:
class Factory: public ConnectionFactory
{
private:
virtual Handle doCreate( Params const& ) const { ... }
virtual bool isValid(
};
};

It splits things up very nicely in terms of responsibility, the
communication lines are very clear (as opposed to communication via
member variables, which is almost the same as global variables), and
there is no call of non-constructor function on uninitialized object.

Cheers, & hth.,

- Alf
 
J

James Kanze

Technically, it's perfectly fine to call virtual functions in
the constructor as long as you understand that it will not
invoke any possible derived-class's overriding version of the
same method. Also, your compiler will complain if you're
calling a pure virtual function.
However, semantically speaking, it seems weird why you would
want to invoke a method that your object wishes to override.

What's so wierd about it? A virtual function is resolved to the
dynamic type of the object. Until you've at least entered the
constructor for the derived type, there's no derived type in
view, and the dynamic type is, logically, the type you are
constructing.
I can't pinpoint it yet, but it seems like a bad design.

Java does call the virtual function in the future dynamic type.
With somewhat disasterous results---you end up calling a
function on an object whose constructor has not yet started.

In practice, of course, you cannot even call all of the
non-virtual member functions in the constructor. In order to be
able to call a member function on an object before the
constructor has started, the member function must be specially
designed to be able to handle a partially constructed object.
 
P

Pavel

....
....

I think you meant to write "It can hardly be argued that initialization
is only supposed to operate on initialized objects".
No, I meant what I said -- that initialization is what makes an object
initialized, so it, by design, is supposed operate on the objects that
are not yet initialized (ok, maybe not necessarily "only").
In C++ this is dealt with by constructors, which, as opposed to other
member functions, operate on not-yet-initialized objects.
This is not true. The Standard allows calling "other member functions"
from the constructor and these functions operate on not-yet-initialized
objects with pre-determined results -- even virtual functions -- unless
the virtual call "uses an explicit class member access". So, the
Standard is OK with the member functions operating on
not-yet-initialized object.

What is not allowed is "referring to a nonstatic member before the
constructor begins execution" and that's what I would like to see
relaxed to allow at least an access to non-static member *functions*,
because, contrary to its name, constructor does not "construct" an
object in memory, but initializes it. Member functions do not require
initialization in constructor; in fact, nothing of a member function can
be changed in the constructor; therefore, unless it reads, directly or
indirectly, some uninitialized *data* members, its call would do no harm.
The problem with Java's virtual calls from constructors can be restated
in these terms, that that mechanism does not deal with that problem.

Specifically, that it causes member functions other than constructors to
operate on not-yet-initialized objects (or more precisely, for Java, on
objects that have not yet had their class invariants established).
Just replace the word "causes" to "allows" and I will agree with the
facts in your statement. As for your conclusion ("the problem"),
however, it may or may not be the problem in each particular case of
using it but it is definitely not the problem of the language. It is a
feature, sometimes useful (not very often but not extremely rarely,
either) and dangerous when misused at the same time.
What's wrong is the earlier "This way...", the virtual call (in Java and
some other languages) in the constructor invoking a function
implementation in a derived class.
See above
That is not necessary in order to keep all validation in the
constructor, nor is it necessary in order to ensure that client code
only has access to valid objects.
It is one way of making sure the client code always accesses
the valid object -- which is the "best practice" I referred to. I have
never stated it was the only way, so I do not think we have a
disagreement here.

....
The above was a precise (well, OK, not that precise!) technical
description.

Coming from rural Northern Norway, you know, fishermen and such, I can
assure you that when I resort to name calling, you'll know it... :).

See <url: http://en.wikipedia.org/wiki/Anti-pattern> for a general
introduction to antipatterns.
Well, I agree they give a reasonable definition. It is more or less in
line with direct GoFs definition of a pattern. According to Wikipedia,
to be an anti-pattern:

1. A pattern of actions must be "repeated" -- compare to GoF's involving
a solution for a "general design problem" in their problem definition.

2. It must "ultimately produce" the "bad consequences outweighing the
hoped-for advantages"

3. A refactored solution must be "clearly documented, proven in actual
practice and repeatable"

My problem does not fit a single bit of the above definition. It is:

1. Specific, just a case to address the Kira's question to the original
poster "why you would want to invoke a method that your object wishes to
override"

2. Does not produce (in Java) or would not produce (in the hypothetical
C++ example) any bad consequences.

3. The suggested alternatives (including my own for C++) are worse than
the original course of actions. They add unnecessary complexity and do
not address an issue in the original solution (because, IMHO, there is
no issue).
Doing a Google search for a name of this particular antipattern didn't
turn up any hits.

However, since it is an antipattern it's called an antipattern here &
there on the net, e.g. <url:
http://mehranikoo.net/CS/archive/2006/11/28/InstanceConstructors.aspx>
and <url: http://debasishg.blogspot.com/2006_11_01_archive.html> (which
indicates the Eclipse can detect this antipattern automatically).
The first referenced article states that the "Template Method" pattern
becomes an anti-pattern if used in Constructors. I was far from stating
the opposite, my context is much more narrow -- how to re-factor the
constructor code to address the particular valid business requirement.
Once again, we are discussing a particular problem and whether or not
the tool (C++) is helpful enough to solve it.

Your second reference is from really afar field. It demonstrates how
Java aspects fire a thread that would access an incompletely constructed
object. Not sure how it is relevant -- the class constructor does not
have to call any virtual methods of its class to create such a problem.
Again, this demonstrates the misuse of a language feature -- explicit
thread support in Java. If C++ supported threads, same misuse would be
possible in C++. I hope nobody suggests to ban the Thread support due to
the possibility of this misuse (I admit this case is much more extreme
than in our case).

....
Perhaps you may find my original sketch for that item more clear, <url:
http://home.no.net/alfps/cpp/faq_proposal/@virtual-functions.html#faq-20.7>
I read it, thank you. Your part-creator solution is probably the best to
to solve my sample case and is similar to my own alternative solution
(in both design and, unfortunately, the complexity)
It would go like (off the cuff)

class ConnectionFactory
....
Handle create( Params& const params ) const
Add one more class for Handle
....
....
class FooConnection
....
class OracleFooConnection : public FooConnection
....
class Factory: public ConnectionFactory ....
> It splits things up very nicely in terms of responsibility, the
> communication lines are very clear (as opposed to communication via
> member variables, which is almost the same as global variables), and
> there is no call of non-constructor function on uninitialized object.

You solution illustrates the point I am trying to make really well --
thank you, no irony here. We ended up with 5 non-trivial communicating
classes (ConnectionFactory, Handle, FooConnection, OracleFooConnection,
Factory), because our requirement was:

"I want to factor out some code that is common for all classes in my
class hierarchy and is supposed to be called *after* the class-specific
code when I initialize my objects"

If only our requirement had the word *before* in place of *after* above,
we would undoubtedly have to write only 2 classes (FooConnection and
OracleFooConnection) and the communication would be really trivial,
nothing to talk about.

Isn't it obvious that our tool of choice (C++) stands in our way in this
particular case? Of course we can appease ourselves that we accomplished
more than just solving the original problem (implemented the Factory and
Handle "mini-frameworks" in your solution and implemented Factory
mini-framework and reduced the dependence of the client code on the
implementation in my solution -- I threw in some Bridge) but..

- who asked us to do all that?
- who is going to pay for all that (in money or project time) if we
don't need to re-use all that and it was not asked for?
- who is going to test all that if it was not required by the business
and pay for that, too?
- who is going to document all those clear communication lines and then
talk every newcomer to the team into following our "right ways"? They
may be right but they surely will not be most intuitive for him/her. And
then, s/he has to write a separate Factory for every new FooConnection
and not forget to create that Handle, not a connection itself..

Long story short, is this ban of our little language feature (which we
would know how to use safely) worth the trouble?

..>
Cheers, & hth.,

- Alf
Regards
-Pavel
 
A

Alf P. Steinbach

* Pavel:
...

No, I meant what I said -- that initialization is what makes an object
initialized, so it, by design, is supposed operate on the objects that
are not yet initialized (ok, maybe not necessarily "only").
OK.



This is not true. The Standard allows calling "other member functions"
from the constructor and these functions operate on not-yet-initialized
objects with pre-determined results -- even virtual functions -- unless
the virtual call "uses an explicit class member access". So, the
Standard is OK with the member functions operating on
not-yet-initialized object.

Well here you have misunderstood completely. The sentence you're
quoting from (in §12.7/3) has to do with technically undefined behavior
for use of a possibly not-yet-constructed sub-object within the current
rules, where the example is multiple inheritance. First and most
important, technical UB is /not/ the problem we're discussing. Second,
even within that context, "uses an explicit class member access" is a
misleadingly incomplete quote, because what's important about that
sentence, with respect to UB (which is not what we're discussing), is
the qualification that the sentence continues with. C++ does absolutely
not, in general, forbid a constructor calling a virtual function that
uses an explicit member access. So when you write "This is not true"
it's a kind of Hofstadter'esque paradoxical self-reference... :)

I'm amazed that you chose to interpret my paragraph as if I were unaware
of e.g. init-functions, given that the article you responded to referred
you to my own discussion of them.

I think choosing such a silly interpretation is a bit adversarial.

If had to rewrite my paragraph above so that it would withstand an
adverserial attack, then it would at the end repeat much of the standard
and add about just as much or more about rationales, plus just about as
much about general OO theory and engineering practice, properly peppered
with references to disclaimers "we don't know the standard's rationales"
every fifth character or so -- and it would also involve much
weasel-language and be totally unreadable and ungrokkable, which is
generally what results when one adopts the thinking mode of lawyers.

Suffice it to say, (1) constructors are the tools that C++ give you to
handle the problem of operating on uninitialized objects in order to
initialize them, and (2) in other member functions you can generally
assume that the object is initialized, that the class invariant has been
established.

The weasel language "generally" is for the case of e.g. an init-function
or other construction helper.

And the importance of (2) is not technical UB, although ignoring (2) can
in the end result in UB, but it is that other member functions in
general have much stronger assumptions, that those assumptions would
easily be violated if virtual calls down to derived classes were allowed
in constructors, and that this type safety aspect is the rationale
(insert disclaimer about knowing rationales) for the C++ rules.

E.g. in the words of FAQ item 23.5, "C++ is protecting you from serious
and subtle bugs", "if the above rule were different, you could easily
use objects before they were initialized, and that would cause no end of
grief and havoc", or, read Bjarne's discussion about class invariants,
What is not allowed is "referring to a nonstatic member before the
constructor begins execution" and that's what I would like to see
relaxed to allow at least an access to non-static member *functions*,
because, contrary to its name, constructor does not "construct" an
object in memory, but initializes it. Member functions do not require
initialization in constructor

They do. In most implementations, calling a virtual member function
requires that a proper vtable pointer has been established. And that's
the constructor's responsibility -- it just happens under the hood.

in fact, nothing of a member function can
be changed in the constructor; therefore, unless it reads, directly or
indirectly, some uninitialized *data* members, its call would do no harm.

I think what you mean is that you'd like the ability, some mechanism, to
call a virtual member function, from a class X constructor, with *this
treated as an object of the most derived type (a class derived from X),
if that member function's definition would have been legitimate in X and
ditto for all member functions that it calls directly or indirectly.

And I think that would be very hard to specify in detail (to enforce).

However, if a member function doesn't access any member data at all, and
only calls functions that don't access member data, then we're talking.

That would be the often wished for "static virtual", a member function
that can be called virtually but doesn't have /access/ to a 'this'
pointer. Except for the ability to be called virtually on derived class
from a constructor, it can be emulated by a pair of member functions,
namely one virtual member function that (only) calls a static member
function doing the work. It would be nice with special syntax for that.

One way of resolving what should happen if such a function itself calls
a "static virtual" function is that the member functions calls it makes
in turn will always be non-virtual.

Just replace the word "causes" to "allows" and I will agree with the
facts in your statement.

"Allows" implies in-practice "causes". :)

We're talking about practical implications.

As for your conclusion ("the problem"),
however, it may or may not be the problem in each particular case of
using it but it is definitely not the problem of the language. It is a
feature, sometimes useful (not very often but not extremely rarely,
either) and dangerous when misused at the same time.

Java's rules for virtual calls in constructors are language problem,
because (1) the problem can easily be prevented by suitable language
rules, such as in C++, and (2) without that type safety, the language
encourages the practice of non-type-safe design and coding.

See above

It is one way of making sure the client code always accesses
the valid object -- which is the "best practice" I referred to. I have
never stated it was the only way, so I do not think we have a
disagreement here.

I think I begin to understand why "final" classes are so popular in Java.

For if client code could derive from any such class, then the code would
not ensure that client code only had access to valid objects.

Deriving from a class using that non-type-safe idiom is a very easy way
to gain access to a non-initialized object.

As it happens that's also a problem with the init-function solution in
C++, e.g., as used by Microsoft's ATL library -- you can easily end up
with a call of a virtual function where the object isn't yet properly
initialized.

The difference is that with the C++ init-function the programmer has
intentionally refrained from using the proper language mechanism,
presumably in order to avoid its type safety (poor programmers often do
that, hey this thing doesn't let me do what I want to!), whereas with
the Java constructor's virtual call it is the language mechanism that
otherwise would be the proper one, that commits this novice error.

...


Well, I agree they give a reasonable definition. It is more or less in
line with direct GoFs definition of a pattern. According to Wikipedia,
to be an anti-pattern:

1. A pattern of actions must be "repeated" -- compare to GoF's involving
a solution for a "general design problem" in their problem definition.

2. It must "ultimately produce" the "bad consequences outweighing the
hoped-for advantages"

3. A refactored solution must be "clearly documented, proven in actual
practice and repeatable"

My problem does not fit a single bit of the above definition. It is:

1. Specific, just a case to address the Kira's question to the original
poster "why you would want to invoke a method that your object wishes to
override"

Java's virtual-call-from-constructor is, in your own words quoted above,
"not extremely rarely, either".

So yes, it is a repeated pattern.

So often repeated that evidently Java tools such as Eclipse can detect
that automatically.


2. Does not produce (in Java) or would not produce (in the hypothetical
C++ example) any bad consequences.

Ending up with a call of a virtual function on a not-yet-initialized
object is very common, and the abundance of bugs in Java programs
resulting from that really does count as bad consequences.

3. The suggested alternatives (including my own for C++) are worse than
the original course of actions. They add unnecessary complexity and do
not address an issue in the original solution (because, IMHO, there is
no issue).

If you deny that there is any issue, then of course the little
superficial complexity to avoid that issue seems unnecessary.

However, the complexity is inherent in the problem: glossing over by
using member variables for communication (hiding the communication) and
using unexpressed assumptions about what can be safely accessed (hiding
the uninitialized issue and order of operations issues), does not make
that inherent complexity go away, it's just a glossing over, hiding.

You here choose superficial simplicity over addressing underlying
problems and exposing actual, inherent complexity (even if there's not
much of it!). It's much like not doing unit-tests or not writing any
documentation whatsoever, as one person I talked with proudly explained
that his company did. It goes only to the zeroth level of perception,
less work right now for me, and therefore obviously less work in total.
It's like marrying a girl because one is infatuated with her glorious
cosmetics and delightful perfume, ignoring what comes after that.

The first referenced article states that the "Template Method" pattern
becomes an anti-pattern if used in Constructors. I was far from stating
the opposite, my context is much more narrow -- how to re-factor the
constructor code to address the particular valid business requirement.
Once again, we are discussing a particular problem and whether or not
the tool (C++) is helpful enough to solve it.

Your second reference is from really afar field. It demonstrates how
Java aspects fire a thread that would access an incompletely constructed
object. Not sure how it is relevant -- the class constructor does not
have to call any virtual methods of its class to create such a problem.
Again, this demonstrates the misuse of a language feature -- explicit
thread support in Java. If C++ supported threads, same misuse would be
possible in C++. I hope nobody suggests to ban the Thread support due to
the possibility of this misuse (I admit this case is much more extreme
than in our case).

Both articles use the term antipattern for the general notion of virtual
call from constructor in Java. And presumably that's also what Eclipse
detects, not whether there is a template pattern or threads involved...

...
I read it, thank you. Your part-creator solution is probably the best to
to solve my sample case and is similar to my own alternative solution
(in both design and, unfortunately, the complexity)

...
Handle create( Params& const params ) const
Add one more class for Handle
...
...
class FooConnection
...
class OracleFooConnection : public FooConnection
...

You solution illustrates the point I am trying to make really well --
thank you, no irony here. We ended up with 5 non-trivial communicating
classes (ConnectionFactory, Handle, FooConnection, OracleFooConnection,
Factory), because our requirement was:

"I want to factor out some code that is common for all classes in my
class hierarchy and is supposed to be called *after* the class-specific
code when I initialize my objects"

If only our requirement had the word *before* in place of *after* above,
we would undoubtedly have to write only 2 classes (FooConnection and
OracleFooConnection) and the communication would be really trivial,
nothing to talk about.

Isn't it obvious that our tool of choice (C++) stands in our way in this
particular case?

On the contrary, it forces you to at least think about the problem and
choose some solution intentionally, instead of blindly doing the
equivalent of non-typed assembly language programming, very happy that
hey, the code "works". The above exposes the notions inherent in the
problem. I think that's much better than hiding them.

Unfortunately C++ does not force you or guide you to a good solution.

However, a special language mechanism for this would further complicate
an already quite complicated language.

Of course we can appease ourselves that we accomplished
more than just solving the original problem (implemented the Factory and
Handle "mini-frameworks" in your solution and implemented Factory
mini-framework and reduced the dependence of the client code on the
implementation in my solution -- I threw in some Bridge) but..

- who asked us to do all that?

The problem itself has all this in it.

- who is going to pay for all that (in money or project time) if we
don't need to re-use all that and it was not asked for?

On the contrary, who pays for the consequences of all of thouse
countless Java bugs resulting from virtual calls from constructors, and
for the bugs resulting from the general practice of not expressing
design or problem level types as types in the code?

There isn't much cost up-front for doing things properly. Those costs
(which for the virtual call thing itself amounts to three or four extra
lines) are negligible.

Your itemization of classes leads me to suspect that in your preferred
solution there wouldn't even be a class or type Handle, i.e. an as much
as possible un-typed solution, which means not expressing restrictions.
Not expressing restrictions means that the compiler can't help deduce
violations of such restrictions. That means more bugs and higher costs,
but it may of course not be blindingly obvious where they stem from.

- who is going to test all that if it was not required by the business
and pay for that, too?

Again, on the contrary: who's paying for the extra work involved in
testing code that doesn't express design level restrictions? With such
code proper testing must check that the design level restrictions aren't
violated. In practice that means complete coverage testing and still
only having a vague probability that the code might be OK.

- who is going to document all those clear communication lines and then
talk every newcomer to the team into following our "right ways"? They
may be right but they surely will not be most intuitive for him/her. And
then, s/he has to write a separate Factory for every new FooConnection
and not forget to create that Handle, not a connection itself..

Again, on the contrary, who is going to document the communication lines
in your code, with communication via member variables (effectively about
the same as communication via global variables)? I'm pretty sure that
these communication lines, ording issues and responsibilities are /not/
documented at all, but if they are, then that documentation must of
necessity be much more verbose and detailed than for the case where it's
expressed directly in the code, and then it amounts to a non-enforcable
comment, instead of as with proper design, enforced by compiler. I.e.,
you're here requiring a much higher standard of documentation for the
clear code where that documentation isn't needed, than for the
hide-the-issues code where the documentation is very much needed.

Long story short, is this ban of our little language feature (which we
would know how to use safely) worth the trouble?

There is no trouble with the C++ rules, as far as I can see.

The trouble is with not enforcing type safety, as in Java and some other
languages.

And the up-front cost of doing things properly is negligible.


Cheers, & hth.,

- Alf
 
P

Pavel

In C++ this is dealt with by constructors, which, as opposed to other
I think choosing such a silly interpretation is a bit adversarial.
Again, no pun was intended. I simply do not know how else to interpret
your "constructors, as opposed to other member functions, operate on
not-yet-initialized objects". If a constructor calls another member
function why can not that function operate on "not-yet initialized
object"? Does not it make your statement not true?

I am deleting most of your other post because I agree to it -- simply do
not understand how it is related to our subject.
E.g. in the words of FAQ item 23.5, "C++ is protecting you from serious
and subtle bugs", "if the above rule were different, you could easily
use objects before they were initialized, and that would cause no end of
grief and havoc", or, read Bjarne's discussion about class invariants,
at <url: http://www.research.att.com/~bs/3rd_safe0.html>.
Well, please agree there are much easier ways to "cause no end of grief
and havoc" in C++. And it was Bjarne's promise about the language's
allowing blowing off my whole leg if I try a little harder.

On a more serious note, the (vaguely) relevant part of the text in your
reference (I believe you meant
http://www.research.att.com/~bs/3rd_safe.pdf, did not you?) states that
it is the responsibility of the constructor to either establish the
invariants or throw an exception if the invariant cannot be established.
I could not agree more and that's exactly what my validate() method
(called from the constructor) does. I hope you do not understand this
idiom as literally establishing invariant in the constructor code, not
being able to break down the constructor's logic onto smaller functions
even if establishing the invariant would take 10000 lines of source
code. Your solution delegates these responsibilities to doCreate(). By
the way, to do anything useful in doCreate(), your Factory must be a
friend of a Handle or something similar -- not too clear a line..)

Frankly, if you agree that it is ok for a constructor to call other
member functions (virtual or not) for the purpose of initialization of
some or all of the object's data members, we do not have a disagreement
here -- otherwise, please suggest an alternative.
They do. In most implementations, calling a virtual member function
requires that a proper vtable pointer has been established. And that's
the constructor's responsibility -- it just happens under the hood.
Member functions do *not* require it. That some implementations choose
to initialize vtable this way does not constitute the need to do it
(except maybe for that very rule of selecting which virtual function is
called in constructor that we discuss and about which I am making my
point that this rule is not useful). Compiler has complete knowledge of
the class hierarchy of an object including its most derived type at the
point in the code where the object is created so the complier has all
necessary information to insert the code constructing the object's
storage layout in general and vtables (if needed) in particular before
calling the first base class's constructor. I think I am repeating
myself though.
I think what you mean is that you'd like the ability, some mechanism, to
call a virtual member function, from a class X constructor, with *this
treated as an object of the most derived type (a class derived from X),
if that member function's definition would have been legitimate in X and
ditto for all member functions that it calls directly or indirectly. True.


And I think that would be very hard to specify in detail (to enforce).
Java does it. Not difficult at all: first build the object's storage
layout completely, then enter the code for the very first constructor.
As for the requirement language, I am as unwilling to cite pages of Java
Language Specification as you -- the pages of C++ Standard. Enough to
say, it has been done before, with little troubles.
However, if a member function doesn't access any member data at all, and
only calls functions that don't access member data, then we're talking.
No, not that I meant although it is a useful concept that you mention,
but not for this example. In this example, the member function must
access members (namely to initialize them) -- it does not have to read
them though, only write... I am deleting some more of your post related
to the above.
"Allows" implies in-practice "causes". :)

We're talking about practical implications.
Again you try to make me look defending some "patterns" or similar
general concept. I am just trying to solve a particular problem whose
solution is clearly overcomplicated by the language's rules. No, in my
pseudo-code there is nothing wrong: the operation on not-yet-initialized
objects is correct, namely, it makes them already-initialized :).
Java's rules for virtual calls in constructors are language problem,
because (1) the problem can easily be prevented by suitable language
rules, such as in C++, and (2) without that type safety, the language
encourages the practice of non-type-safe design and coding.
What do reinterpret_cast and pointer arithmetic encourage :)? Let's be
serious, Java type safety is enforced (as opposed to the one by C++).
Let's do not make assumptions either: this is the rule that you call
reasonable makes me write 5 classes instead of 2 (in my solution,
actually, 6 :-( -- you are better in that, but I achieve better
readability and some side advantages, imho. I will paste my solution at
the end of this post to avoid being pointless).
I think I begin to understand why "final" classes are so popular in Java.
Are they? I do not meet them often.
For if client code could derive from any such class, then the code would
not ensure that client code only had access to valid objects.
Well, this is one effect that is achieved by `final'. Also, the compiler
is free to inline final function calls (in the extreme case of final
class -- all of them if it feels like it. C++ compiler does not have
this luxury when one member function calls another, virtual member
function of the same class). And certainly there are other uses.
Deriving from a class using that non-type-safe idiom is a very easy way
to gain access to a non-initialized object.
Doesn't any member function of a class called from its constructor have
such access?
As it happens that's also a problem with the init-function solution in
C++, e.g., as used by Microsoft's ATL library -- you can easily end up
with a call of a virtual function where the object isn't yet properly
initialized.

The difference is that with the C++ init-function the programmer has
intentionally refrained from using the proper language mechanism,
presumably in order to avoid its type safety (poor programmers often do
that, hey this thing doesn't let me do what I want to!), whereas with
the Java constructor's virtual call it is the language mechanism that
otherwise would be the proper one, that commits this novice error.
Again, I am trying to get away from generalizing. In my example, the
programmer just wants to factor its initialization code according to its
responsibilities -- and has a problem doing that.
Java's virtual-call-from-constructor is, in your own words quoted above,
"not extremely rarely, either".

So yes, it is a repeated pattern.
No, I am saying "the language feature is sometimes useful, not extremely
rarely". A language feature is not a pattern -- it is like a hammer. It
can build a palace if used in nice "nail driving" pattern (course of
actions) or it can kill if used in the ugly "murdering" anti-pattern.
But the hammer is not a pattern or course of action by itself.
So often repeated that evidently Java tools such as Eclipse can detect
that automatically.
not really often. There are historical reasons why Java crowd is so loud
about this particular issue but the discussion would take us too far away.

Ending up with a call of a virtual function on a not-yet-initialized
object is very common, and the abundance of bugs in Java programs
resulting from that really does count as bad consequences.
Please.. I find it really ironic that I am put in the position where I
almost started defending Java safety vs C++. It would start another holy
war and Java would prevail (and no, I am not a Java adept, I started
with Fortran 66 and I can always prove it is safer and in general beats
any other PL hands down :) ).

But please please please do not make me responsible for all bad Java (or
C++, for this matter) code around. Just see the hammer metaphor above.
If you deny that there is any issue, then of course the little
superficial complexity to avoid that issue seems unnecessary.

However, the complexity is inherent in the problem: glossing over by
using member variables for communication (hiding the communication) and
using unexpressed assumptions about what can be safely accessed (hiding
the uninitialized issue and order of operations issues), does not make
that inherent complexity go away, it's just a glossing over, hiding.
I am probably blind but I do not see this complexity -- and usually I am
quite good at it. All is required is to execute some common code every
time right after class-specific part of initialization. How complex can
that be?
You here choose superficial simplicity over addressing underlying
problems and exposing actual, inherent complexity (even if there's not
much of it!).
there is none in Java solution. You attack the valid solution from the
position that the language feature it uses is misused by some other
code. Every non-trivial C++ feature is misused by some code floating
around (and maybe every trivial one, too). What does it prove to you?
Not that all non-trivial C++ features features should be eliminated, I hope.

It's much like not doing unit-tests or not writing any
documentation whatsoever, as one person I talked with proudly explained
that his company did. It goes only to the zeroth level of perception,
less work right now for me, and therefore obviously less work in total.
....
Other way around. I anticipate (from the experience, not just pure
logic) how many times the people will not read my documentation, how
many times they will abuse every line of the code they get to support,
especially if they did not write it, especially if the code does not
seem to be related to the problem in hand, how many times they will
stumble upon the non-obvious code, will not ask questions but instead
start re-inventing their own wheels or assume etc. etc. etc.. Extra code
== extra liability, believe me. After your project is 2-3 years old you
will see the ugly remnants of 24 different "frameworks" and "right ways"
in the code, of which half does one same thing in 12 different ways and
another half does the second thing.

Both articles use the term antipattern for the general notion of virtual
call from constructor in Java.
BTW, the second article is not even about Java at all (not sure why the
author says "Java") -- see the code snippet -- it is some
aspect-oriented JVM-based language (AspectJ, maybe). But if you insist
on using the pattern terminology, why don't you start with the
rationale? My little example is far from the rationales behind the
[anti]patterns in those cited articles; and what can be an anti-pattern
for a generic problem, can be a valid solution (not a pattern, though)
for another specific problem.

And presumably that's also what Eclipse
detects, not whether there is a template pattern or threads involved...
I am unsure, too. Would be interested to know though.
On the contrary, it forces you to at least think about the problem
Agree. And much more than absolutely necessary at that.. System 360
Assembler or Turing machine would make me think even yet more.. about
things irrelevant to my business requirements.. what good would it do me?
choose some solution intentionally,
> instead of blindly doing the
equivalent of non-typed assembly language programming,
any specifics?

very happy that
hey, the code "works". The above exposes the notions inherent in the
problem. I think that's much better than hiding them.
IMHO, Handle and Factory are equally inherent (or not) to any problem
involving any object creation/operation. I cannot see how they are more
inherent to this particular problem.
Unfortunately C++ does not force you or guide you to a good solution.

However, a special language mechanism for this would further complicate
an already quite complicated language.
Well, how a virtual function call in constructor is routed seems generic
enough mechanism to me. The feature is generic, it is the problem is
specific. As for the relative complexity of 2 approaches, I doubt we can
agree here because we, in fact, throwing opinions, not measuring. IMHO,
the current C++ behavior in that is more complicated and error-prone
than the one of Java, honestly, but I do not even try to change your
viewpoint on this. Unless we agree on some methodology of comparison,
there is no chance I will change my, either.
The problem itself has all this in it.
The problem of uniform validation of a freshly constructed object has
Factory and Handle in it? Can you be a little more specific and explain
where they were hiding?
On the contrary, who pays for the consequences of all of thouse
countless Java bugs
Not our imagined client of our OracleFooConnection -- we did not put in
those bugs, did we? Again, let's stop those groundless "countless" etc
-- these are just opinions. Objective representative statistics on bugs
are expensive to receive and interpret -- but I doubt C++ code has less
bugs to offer. Why don't we stick to the point? Fixing the world is not
an enterprise I would invest into.

resulting from virtual calls from constructors, and
for the bugs resulting from the general practice of not expressing
design or problem level types as types in the code?

There isn't much cost up-front for doing things properly. Those costs
(which for the virtual call thing itself amounts to three or four extra
lines) are negligible.
see above about upfront cost (after my "Other way around"). Maintenance
is the key for me -- but, BTW, it is usually more difficult to get a
budget for the upfront costs so they are "costlier" per dollar or per
hour, so to say.
Your itemization of classes leads me to suspect that in your preferred
solution there wouldn't even be a class or type Handle, i.e. an as much
as possible un-typed solution, which means not expressing restrictions.
I am confused again. I would not use Handle, true. Un-typed solution? My
"not-C++" solution was in my first post and my real solution (working in
C++ as it is now) is at the bottom of this post. I am not sure how any
of them is untyped. I feel the second one is even "over-typed" a little.
But it does not use Handle, what's true is true.
Not expressing restrictions means that the compiler can't help deduce
violations of such restrictions. That means more bugs and higher costs,
but it may of course not be blindingly obvious where they stem from.
Agree but again, how is it relevant? What specific restrictions do you
mean that 2-class solution would break and 5-class solution does not?
Again, on the contrary: who's paying for the extra work involved in
testing code that doesn't express design level restrictions? With such
code proper testing must check that the design level restrictions aren't
violated. In practice that means complete coverage testing and still
only having a vague probability that the code might be OK.
Can you please enumerate the restrictions you mean in our case? I beg
you do be more specific, it will spare both of us a lot of time and effort.
Again, on the contrary, who is going to document the communication lines
in your code, with communication via member variables (effectively about
the same as communication via global variables)? I'm pretty sure that
these communication lines, ording issues and responsibilities are /not/
documented at all, but if they are, then that documentation must of
necessity be much more verbose and detailed than for the case where it's
expressed directly in the code, and then it amounts to a non-enforcable
comment, instead of as with proper design, enforced by compiler. I.e.,
you're here requiring a much higher standard of documentation for the
clear code where that documentation isn't needed, than for the
hide-the-issues code where the documentation is very much needed.
Again, please could you be more specific? What code do we refer to? What
member variables?
There is no trouble with the C++ rules, as far as I can see.
I hoped I was able to demonstrate the trouble (not of C++ but of its
user) above; it is the necessity to write a lot of code tangential to
the problem in hand, which could be avoided under more logical (IMHO
only) and broadly used in practice (Java) rules.
The trouble is with not enforcing type safety, as in Java and some other
languages.
no comments. If I did not just delete what I wrote in response on a
whim, I would be responsible for inflaming another holy war. Please
let's stop comparing merits of different languages. I am guilty in
bringing in Java but I did it only as a working example of how objects
could be built differently in C++, not to praise Java or attack C++.
And the up-front cost of doing things properly is negligible.
We both are repeating ourselves, aren't we? See above..

The solution "in current C++" I promised earlier (6 classes, you do not
have to count. My "communication lines" seem to be a little clearer than
yours but I would first agree it is an opinion. I would gladly give up
all those lines for more straightforward mapping from the business to
the implementation language, as in the former "would-be C++" example):

// ---------- public code (supplied with the binary distribution)
typedef int Param; // just for example; some data type
typedef int FooException; // just for example; some exception type
struct FooConnectionImpl;
struct FooConnectionImplFactory;
class FooConnection {
public:
virtual void doSomethingUseful() = 0;
protected:
void validate() const throw(FooException &);
virtual ~FooConnection();
FooConnection(const Param &, const FooConnectionImplFactory *);
FooConnectionImpl *impl;
};

class OracleFooConnection : public FooConnection {
public:
void doSomethingUseful(); // at last..
public:
OracleFooConnection(const Param &);
};

// --------- client code
int main(int argc, char *argv[]) {
OracleFooConnection c(25);
c.doSomethingUseful();
return 0;
}

// --------- private code (the client's compiler does not need to see
this code)
#include <iostream>
using namespace std; // just for the sake of brefity, don't shoot
struct FooConnectionImpl { // the parallel hierarchy root
virtual ~FooConnectionImpl() {}
};

void FooConnection::validate() const throw(FooException &) {
// SELECT foo_version from FOO_MAIN_TABLE here for example
// or some other common code. In practice will use FooConnectionImpl
interface.
}

FooConnection::~FooConnection() { delete impl; }

struct FooConnectionImplFactory {
virtual FooConnectionImpl* create(const Param &) const = 0;
};

FooConnection::FooConnection(const Param &param, const
FooConnectionImplFactory *factory) {
impl = factory->create(param);
}

void OracleFooConnection::doSomethingUseful() {
cout << "do something useful already\n";
}

struct OracleFooConnectionImpl : public FooConnectionImpl
{
OracleFooConnectionImpl(const Param &p) { /*...*/ }
/*Oracle-specific stuff here*/
};

struct OracleFooConnectionImplFactory : public FooConnectionImplFactory
{
FooConnectionImpl *create(const Param &p) const
{ return new OracleFooConnectionImpl(p); }
static OracleFooConnectionImplFactory instance; // just a shortcut
here, do not want to go all the way
}; // w. real singletons etc

OracleFooConnectionImplFactory OracleFooConnectionImplFactory::instance;

OracleFooConnection::OracleFooConnection(const Param &p)
: FooConnection(p, &OracleFooConnectionImplFactory::instance)
{ /* Oracle-specific initialization here */ }
Cheers, & hth.,

- Alf

Regards,
-Pavel
 
A

Alf P. Steinbach

* Pavel:
In C++ this is dealt with by constructors, which, as opposed to
other member functions, operate on not-yet-initialized objects.

This is not true. The Standard allows calling "other member
functions" from the constructor and these functions operate on
not-yet-initialized objects with pre-determined results -- even
virtual functions -- unless the virtual call "uses an explicit class
member access". So, the Standard is OK with the member functions
operating on not-yet-initialized object.
[counter to that + some context was snipped, see up-thread]

I think choosing such a silly interpretation is a bit adversarial.

Again, no pun was intended. I simply do not know how else to interpret
your "constructors, as opposed to other member functions, operate on
not-yet-initialized objects". If a constructor calls another member
function why can not that function operate on "not-yet initialized
object"? Does not it make your statement not true?

First, just to recap some of what you snipped, an init-function is an
example of a function that does that, technically.

And a statement is not untrue just because there exists a possible
meaningless interpretation.

Think about calls from client code.

In particular, even a private virtual function can be called in client
code that derives from the class in question, and that client code
implementation can then very easily see an uninitialized *this object.

And the other way, it might end up calling other functions that the
client code overrides.

But note that that problem is not /that/ severe in Java because Java
also has another severe problem -- non-deterministic not-guaranteed
destruction -- that often necessitates a two-level class invariant
(object is zombie OR real class invariant) and ditto peppering of checks
of whether the meta-level of being a zombie object, holds, so that
preventive checking of whether the object is a zombie object, in every
member function, isn't necessarily an extra cost, just usual Java...

In passing, check out[1] <url:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6596304>. :)



[snipped rest]


Cheers, & hth.,

- Alf

Notes:
[1] That bug report refers to a blog that provides a "solution" that
doesn't work for multiple levels of inheritance, and that relies on
documentation instead of compiler enforcement, best ignored, or perhaps
taken as evidence that at least one blogging Java programmer and one
Java bug report responder do not grok the complete picture.
 
P

Pavel

Alf said:
* Pavel:
In C++ this is dealt with by constructors, which, as opposed to
other member functions, operate on not-yet-initialized objects.

This is not true. The Standard allows calling "other member
functions" from the constructor and these functions operate on
not-yet-initialized objects with pre-determined results -- even
virtual functions -- unless the virtual call "uses an explicit class
member access". So, the Standard is OK with the member functions
operating on not-yet-initialized object. [counter to that + some context was snipped, see up-thread]

I think choosing such a silly interpretation is a bit adversarial.

Again, no pun was intended. I simply do not know how else to interpret
your "constructors, as opposed to other member functions, operate on
not-yet-initialized objects". If a constructor calls another member
function why can not that function operate on "not-yet initialized
object"? Does not it make your statement not true?

First, just to recap some of what you snipped, an init-function is an
example of a function that does that, technically.

And a statement is not untrue just because there exists a possible
meaningless interpretation.

Think about calls from client code.

In particular, even a private virtual function can be called in client
code that derives from the class in question, and that client code
implementation can then very easily see an uninitialized *this object.
No objections. I do not think we have any disagreement at what
technically happens or can be done by this or that code during
construction call -- but our evaluations of the feature differs. I
believe "Java" ways in this are more useful than dangerous (and the C++
way is roughly equally dangerous but not useful), you believe
otherwise.. I suggest to wrap up our discussion.
And the other way, it might end up calling other functions that the
client code overrides.

But note that that problem is not /that/ severe in Java because Java
also has another severe problem -- non-deterministic not-guaranteed
destruction -- that often necessitates a two-level class invariant
(object is zombie OR real class invariant) and ditto peppering of checks
of whether the meta-level of being a zombie object, holds, so that
preventive checking of whether the object is a zombie object, in every
member function, isn't necessarily an extra cost, just usual Java...
As I said, the last thing I want is to defend Java in general. The
absence of deterministic destruction has made me suffer a lot, for one.
Yes, people make mistakes. JVM Specs is pretty clear about what is
supposed to happen and that is exactly what happens. The relevant piece
of the standard is easy to read and follow:
http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#19124

Hopefully when the "bug" comes to the developer, they will close it
instead of "fixing" it.

[snipped rest]


Cheers, & hth.,

- Alf

Notes:
[1] That bug report refers to a blog that provides a "solution" that
doesn't work for multiple levels of inheritance, and that relies on
documentation instead of compiler enforcement, best ignored, or perhaps
taken as evidence that at least one blogging Java programmer and one
Java bug report responder do not grok the complete picture.

Best Regards,
-Pavel
 
A

Alf P. Steinbach

* Pavel:
Alf said:

Yes, people make mistakes. JVM Specs is pretty clear about what is
supposed to happen and that is exactly what happens. The relevant piece
of the standard is easy to read and follow:
http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#19124
Hopefully when the "bug" comes to the developer, they will close it
instead of "fixing" it.

I think it clearly illustrates the dangers of those virtual calls from
constructors.

For the problem is that code is maintained, not just originally written
(about 80% of coding work is maintainance, as I recall the statistics).

When a maintainance programmer (which might be oneself) comes along and
e.g. adds an initializer to a class member, or falls for the temptation
to let the downcalled function do something with or to the derived
class' members, or adds a call there to a function that someone else
will in turn make do something with or to the derived class' members,
perhaps even in a class derived from the derived one, where the context
of the call is not at all clear, then presto, a new bug or set of bugs.


Cheers,

- Alf
 
P

Pavel

Alf said:
* Pavel:
Alf said:

Yes, people make mistakes. JVM Specs is pretty clear about what is
supposed to happen and that is exactly what happens. The relevant
piece of the standard is easy to read and follow:
http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#19124

Hopefully when the "bug" comes to the developer, they will close it
instead of "fixing" it.

I think it clearly illustrates the dangers of those virtual calls from
constructors.

For the problem is that code is maintained, not just originally written
(about 80% of coding work is maintainance, as I recall the statistics).

When a maintainance programmer (which might be oneself) comes along and
e.g. adds an initializer to a class member, or falls for the temptation
to let the downcalled function do something with or to the derived
class' members, or adds a call there to a function that someone else
will in turn make do something with or to the derived class' members,
perhaps even in a class derived from the derived one, where the context
of the call is not at all clear, then presto, a new bug or set of bugs.

I guess it is the problem with any framework, isn't it? A framework (be
it a Template Method, Factory or operator overloading) has to rely on
the maintenance programmer's using rather than abusing it. I am not
aware of a satisfactory protection against the concrete factory's
create() method returning a random integer casted to a pointer, the
semantics of two Template Method's concrete operations being swapped
(which, incidentally, happens a lot) or an overloaded binary operator*
for some Matrix class calculating pair-wise products instead of matrix
product (or other way around).

Certainly a good framework must let its *benevolent* user as clear and
readily available clue of what's expected from him/her as possible. My
opinion is that the name of init() virtual function would give just
right a clue and you disagree, you believe that the Holder/Factory
machinery is less error-prone and reduces maintenance costs and I
disagree. I really doubt we can come to an agreement on this so I
suggest that we disengage.

Cheers,

- Alf

Thank you -- I really enjoyed the discussion and I feel it was useful
for me; hopefully it was at least somewhat entertaining for other group
attendees, too.

Best Regards,
Pavel
 

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,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top