Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why cout not a singleton?

207 views
Skip to first unread message

Ani Taggu

unread,
Apr 27, 2001, 6:43:27 PM4/27/01
to
In <ostream> header:

declaration of std::cout is something like this:
extern ostream cout;

Now, I will use this "non-local static object" cout in the constructor of
the class below.

#include <iostream>
using namespace std;

class SomeLogger
{
public:
// using member func operator<<() of cout ...
SomeLogger() { cout << "some mesg" << endl; } // some other
implementation.
void doSomething() {}
};

SomeLogger theLogger; // global here.

int main()
{
theLogger.doSomething();
return 0;
}

Since "theLogger" is another "non-local static object", I would expect
undefined behavior if cout is initialized after than theLogger because the
constructor for Logger uses its operator<<(), potentially before cout object
is initialized.

So, how does this work? Is cout always guaranteed (by some compiler magic)
to be initialized before any user-defined object? Or shouldn't it be a
singleton [ say cout() ] to handle such cases?

Or do I have a major misunderstanding :( ?

-Ani


[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Ivan Krivyakov

unread,
Apr 28, 2001, 9:19:35 AM4/28/01
to
> declaration of std::cout is something like this:
> extern ostream cout;
>
[...]

> So, how does this work? Is cout always guaranteed (by some compiler magic)
> to be initialized before any user-defined object?

There is no magic.
Well, maybe a little bit :)

First let's observe that inside one translation unit order of initialization
of global objects **is** defined - they are initialized from top to bottom.

In order to use cout, you have to #include <iostream>.
Header file <iostream> contains decalaration of a static object.
In my implementation it looks like

static ios_base::Init _Ios_init;

Here "Init" is a nested class inside class ios_base.
This class has constructor and destructor.

Since _Ios_init is declared static, every translation unit that
#includes <iostream> will have it's own copy of _Ios_init.

All global objects that use cout will occur in the translation unit
below line #include <iostream>.

Therefore, their constructors are guaranteed to be called **after**
constructor of _Ios_init from the same translation unit.

In my implementation constructor of ios_base::Init looks like this:

// standard library implementation file 'iostream.cpp'
int ios_base::Init::_Init_cnt = -1;
....

_CRTIMP2 ios_base::Init::Init()
{ // initialize standard streams first time
bool doinit;
{_Lockit _Lk;
if (0 <= _Init_cnt)
++_Init_cnt, doinit = false;
else
_Init_cnt = 1, doinit = true; }
if (doinit)
{ // initialize standard streams
new (&fin) filebuf(stdin);
new (&fout) filebuf(stdout);
new (&cin) istream(&fin, true);
new (&cout) ostream(&fout, true);
cin.tie(&cout);
new (&ferr) filebuf(stderr);
new (&cerr) ostream(&ferr, true);
cerr.tie(&cout);
cerr.setf(ios_base::unitbuf);
new (&clog) ostream(&ferr, true);
clog.tie(&cout);
}
}

As you can see, it checks whether initialization of cout and other streams
has been done already, and if not - intializes them.

This way cout and friends are always initialized before use, even if they
are used inside a constructor of global object.

Best regards
Ivan

Hans Aberg

unread,
Apr 28, 2001, 3:43:01 PM4/28/01
to
In article <tehvlqd...@corp.supernews.com>, "Ani Taggu"

<ata...@hotmail.com> wrote:
>So, how does this work? Is cout always guaranteed (by some compiler magic)
>to be initialized before any user-defined object? Or shouldn't it be a
>singleton [ say cout() ] to handle such cases?

Yes, you are guaranteed that std::cout will work: Typically one implements
it using a global C++ object that initializes std::cout and the other
standard streams.

C++ programs must have other functions that initializes global C++ objects
before they are used, and terminates them after being used for the last
time. This is usually done before and after the main program has started
and terminated.

These initializer and terminator functions are normally set automatically
by your compiler in a user transparent manner.

But I experienced a case when this was not so, namely, I developed a C++
plugin. Then one had to set these functions by hand.

Consequently, the standard streams did not work, nor did exceptions. After
I had plugged in the C++ initializer and terminator so that they were
called before and after my plugin was called, the program acted normally.

One can use various tricks so that the real initializing of an object only
happens when the program calls for its use for the first time. For
example, one can use a label keeping track if the object has been
initialized, and if it has not, an initializer function is called. Then
the object is only initialized first at the point when it is first called
upon. This lessens the overhead for program that do not use it.

For example, a program that do not use the standard streams will in this
way not initialize them, even though strictly speaking there is probably a
standard stream object lying around somehere in the object code (which the
linker will remove, if it is not used).

Hans Aberg * Anti-spam: remove "remove." from email address.
* Email: Hans Aberg <remove...@member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>

Rintala Matti

unread,
Apr 28, 2001, 5:10:31 PM4/28/01
to
"Ivan Krivyakov" <i.van....@verizon.net> writes:
> First let's observe that inside one translation unit order of initialization
> of global objects **is** defined - they are initialized from top to bottom.
>
> In order to use cout, you have to #include <iostream>.
...

> All global objects that use cout will occur in the translation unit
> below line #include <iostream>.
>
> Therefore, their constructors are guaranteed to be called **after**
> constructor of _Ios_init from the same translation unit.

I've always found this quite annoying. As a class designer it means
that if I have a class which prints out something (debug info,
statistics, etc.) to either cout or cerr, and if I have a slightest
suspicion that someone might create a global variable from my class
(or otherwise create an object from my class before entering main),
then I have to include <iostream> in the class header file (or
document this requirement and hope users read and understand the
documentation). It is even more annoying that I cannot use <iosfwd>,
it has be to <iostream> which is usually quite long and adds to
the compilation time.

Considering that many people and books promote the use of forward
declarations and <iosfwd> in particular, very few warn about classes
whose constructors print something cout or cerr (or clog).

------------ Matti Rintala ----------- bi...@cs.tut.fi ------------
"When the remarkable turns bizarre, reason turns rancid."
Cheshire Cat in "American McGee's Alice"

James Kanze

unread,
Apr 30, 2001, 12:55:46 PM4/30/01
to
Hans Aberg wrote:

> In article <tehvlqd...@corp.supernews.com>, "Ani Taggu"
> <ata...@hotmail.com> wrote:
> >So, how does this work? Is cout always guaranteed (by some compiler
> >magic) to be initialized before any user-defined object? Or
> >shouldn't it be a singleton [ say cout() ] to handle such cases?

> Yes, you are guaranteed that std::cout will work: Typically one
> implements it using a global C++ object that initializes std::cout
> and the other standard streams.

There is no guarantee in the standard. There is also no general
guarantee in any implementation I'm aware of.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

James Kanze

unread,
Apr 30, 2001, 2:30:26 PM4/30/01
to
Ivan Krivyakov wrote:

> > declaration of std::cout is something like this:
> > extern ostream cout;

> [...]
> > So, how does this work? Is cout always guaranteed (by some
> > compiler magic) to be initialized before any user-defined object?

I'm afraid not according to anything I can find in the standard.

> There is no magic. Well, maybe a little bit :)

> First let's observe that inside one translation unit order of
> initialization of global objects **is** defined - they are
> initialized from top to bottom.

> In order to use cout, you have to #include <iostream>. Header file
> <iostream> contains decalaration of a static object. In my
> implementation it looks like

> static ios_base::Init _Ios_init;

This is an extension. (A common one, I hope. It was a requirement in
the classic IO streams, and many people seem to assume that the
standard requires it as well.)

> Here "Init" is a nested class inside class ios_base. This class has
> constructor and destructor.

> Since _Ios_init is declared static, every translation unit that
> #includes <iostream> will have it's own copy of _Ios_init.

> All global objects that use cout will occur in the translation unit
> below line #include <iostream>.

> Therefore, their constructors are guaranteed to be called **after**
> constructor of _Ios_init from the same translation unit.

Attention, however. First, as I said above, this is not guaranteed by
the standard. Second, if the file which contains the declaration
doesn't statically define an std::ios_base::Init, it doesn't help.
This could easily occur if the IO is in a function called from the
constructor of the static object.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Robert Klemme

unread,
Apr 30, 2001, 8:42:55 PM4/30/01
to

Rintala Matti schrieb:


> I've always found this quite annoying. As a class designer it means
> that if I have a class which prints out something (debug info,
> statistics, etc.) to either cout or cerr, and if I have a slightest
> suspicion that someone might create a global variable from my class
> (or otherwise create an object from my class before entering main),
> then I have to include <iostream> in the class header file (or
> document this requirement and hope users read and understand the
> documentation). It is even more annoying that I cannot use <iosfwd>,
> it has be to <iostream> which is usually quite long and adds to
> the compilation time.

you do not have such problems in Java. there is no such thing as a
global variable, there is only static variables. and when a class is
used, it is loaded before and all initializations are done at that
time. so you can be sure that stuff you use is initialized. (ok, i
know that you can construct situations where this does not hold true.
but for 98% of the cases this is true.)

ok, this may seem like the wrong place to post such statements. but we
have shifted to Java for our development (this is why i read and post
here rarely now.) and i have to say it's all those nifty little details
you do NOT have to worry about. from the perspective of software
engineering Java is to my mind the better language.

regards

robert


--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestraße 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert...@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------

Gabriel Dos Reis

unread,
May 1, 2001, 4:48:35 AM5/1/01
to
James Kanze <James...@dresdner-bank.com> writes:

[...]

| > static ios_base::Init _Ios_init;
|
| This is an extension.

There is however a requirement to that effect. See 27.4.2.1.6.

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

Chris Uzdavinis

unread,
May 1, 2001, 4:57:26 AM5/1/01
to
James Kanze <James...@dresdner-bank.com> writes:

> > Yes, you are guaranteed that std::cout will work: Typically one
> > implements it using a global C++ object that initializes std::cout
> > and the other standard streams.
>
> There is no guarantee in the standard. There is also no general
> guarantee in any implementation I'm aware of.


Consider 27.3 p2, and especially footnote 265. It does make some
guarantees.

--
Chris

James Dennett

unread,
May 1, 2001, 9:04:05 AM5/1/01
to
Robert Klemme wrote:
>
> Rintala Matti schrieb:
> > I've always found this quite annoying. As a class designer it means
> > that if I have a class which prints out something (debug info,
> > statistics, etc.) to either cout or cerr, and if I have a slightest
> > suspicion that someone might create a global variable from my class
> > (or otherwise create an object from my class before entering main),
> > then I have to include <iostream> in the class header file (or
> > document this requirement and hope users read and understand the
> > documentation). It is even more annoying that I cannot use <iosfwd>,
> > it has be to <iostream> which is usually quite long and adds to
> > the compilation time.
>
> you do not have such problems in Java. there is no such thing as a
> global variable, there is only static variables. and when a class is
> used, it is loaded before and all initializations are done at that
> time. so you can be sure that stuff you use is initialized. (ok, i
> know that you can construct situations where this does not hold true.
> but for 98% of the cases this is true.)
>
> ok, this may seem like the wrong place to post such statements. but we
> have shifted to Java for our development (this is why i read and post
> here rarely now.) and i have to say it's all those nifty little details
> you do NOT have to worry about. from the perspective of software
> engineering Java is to my mind the better language.

Whilst implementing the proposed Java 1.4 API, I came across
a situation where an uninitialized object was used, because
it was a global variable (in the form of a globally accessible
singleton) which was accessed by other objects during its own
construction (seemingly as an unavoidable part of the API
specification). It's possible to work around the problem,
but Java certainly doesn't make fundamental design problems
like this go away any more than C++ does.

-- James Dennett

Wil Evers

unread,
May 1, 2001, 9:11:33 AM5/1/01
to
In article <3AED73C5...@myview.de>, Robert Klemme wrote:

> you do not have such problems in Java. there is no such thing as a
> global variable, there is only static variables. and when a class is
> used, it is loaded before and all initializations are done at that
> time. so you can be sure that stuff you use is initialized. (ok, i
> know that you can construct situations where this does not hold true.
> but for 98% of the cases this is true.)
>
> ok, this may seem like the wrong place to post such statements. but we
> have shifted to Java for our development (this is why i read and post
> here rarely now.) and i have to say it's all those nifty little details
> you do NOT have to worry about. from the perspective of software
> engineering Java is to my mind the better language.

I'd say this comparison isn't entirely fair. Guaranteed load-time
initialization is a platform feature, not a language feature. If supported
by the target platform, it can be used from C++ in much the same way it is
used from Java. The problem is that if you do, the program becomes
non-portable.

Since Java is both a language *and* a platform, its designers simply
weren't faced with the portability issues the implementors of C++ had to
deal with.

- Wil

--
Wil Evers, DOOSYS IT Consultants, Maarssen, Holland
[Wil underscore Evers at doosys dot com]

James Kanze

unread,
May 2, 2001, 12:18:02 PM5/2/01
to
Robert Klemme wrote:

> Rintala Matti schrieb:

> > I've always found this quite annoying. As a class designer it
> > means that if I have a class which prints out something (debug
> > info, statistics, etc.) to either cout or cerr, and if I have a
> > slightest suspicion that someone might create a global variable
> > from my class (or otherwise create an object from my class before
> > entering main), then I have to include <iostream> in the class
> > header file (or document this requirement and hope users read and
> > understand the documentation). It is even more annoying that I
> > cannot use <iosfwd>, it has be to <iostream> which is usually
> > quite long and adds to the compilation time.

> you do not have such problems in Java.

I've never had any problem with cout or cerr in C++. Generally, the
problem is NOT solvable, so I don't think it is solved in Java. The
load model of Java does minimize it considerably, but at what cost.

> there is no such thing as a global variable, there is only static
> variables. and when a class is used, it is loaded before and all
> initializations are done at that time. so you can be sure that
> stuff you use is initialized. (ok, i know that you can construct
> situations where this does not hold true. but for 98% of the cases
> this is true.)

It's relatively easy to construct cases in Java where you access a
variable before it is correctly initialized. While Java protects you
in this particular case (which isn't hard to avoid in C++, either), it
regularly calls member functions on unconstructed objects, since a
call from the base class constructor resolves to a function in the
derived class. (And this is not an abstract consideration. I can't
count the times I've needed to add code in a member function to verify
that initialization has occured. Mostly in classes derived from
Swing, where the constructors seem to call many functions.)

> ok, this may seem like the wrong place to post such statements. but
> we have shifted to Java for our development (this is why i read and
> post here rarely now.) and i have to say it's all those nifty little
> details you do NOT have to worry about. from the perspective of
> software engineering Java is to my mind the better language.

IMHO, you always have to worry about writing correct code. There are
some features of Java, like garbage collection, which allow you to
write less code without it being incorrect, but globally, I find that
Java creates more problems than it solves when the goal is to write
correct code. The very link model you mention works against you most
of the time, because you are never quite sure what classes the client
code is actually loading; your application doesn't have one version,
but one version per class, which results in more potential versions
than you'll ever be able to test.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

James Kanze

unread,
May 2, 2001, 12:18:40 PM5/2/01
to
Gabriel Dos Reis wrote:

> James Kanze <James...@dresdner-bank.com> writes:

> [...]

> | > static ios_base::Init _Ios_init;

> | This is an extension.

> There is however a requirement to that effect. See 27.4.2.1.6.

I can't find anything to this effect there. The section describes the
class ios_base::Init, but I don't see anything requiring any header
file to contain a static instance of it.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

James Kanze

unread,
May 2, 2001, 12:22:25 PM5/2/01
to
Chris Uzdavinis wrote:

> James Kanze <James...@dresdner-bank.com> writes:

> > > Yes, you are guaranteed that std::cout will work: Typically one
> > > implements it using a global C++ object that initializes
> > > std::cout and the other standard streams.

> > There is no guarantee in the standard. There is also no general
> > guarantee in any implementation I'm aware of.

> Consider 27.3 p2, and especially footnote 265. It does make some
> guarantees.

I should have been more precise. There is no guarantee that you can
simply access one of the standard streams from a constructor of a
static object, and expect anything other than undefined behavior. It
is possible to use them safely from a constructor of a static object,
however, provided the necessary precautions (constructing an instance
of ios_base::Init first) are taken.

There is nothing in 27.3 which suggests otherwise, and since footnotes
are non prescriptive, the footnote can only be interpreted to mean
that there are ways of using the objects safely, not that any use is
safe.

Note that in as far as it goes, this is in no way different from the
classic iostreams. The difference is that in the classic iostreams,
the header file iostream.h was guaranteed to contain a static instance
of this class (or its equivalent). So if the source file in which the
static object was defined included iostream.h before the definition,
it was guaranteed to work.

It might be worth pointing out as well that CFront, and I suspect most
other early C++ compilers, actually initialized the modules in the
reverse order of the order they were incorporated during linking. So
if any object file incorporated after the file with the static object
included iostream.h, using cout or cerr, although not guaranteed,
would in fact work. Since the implementation of the streams included
iostream.h, and it was part of a library which normal link procedures
would incorporate at the end of linking, most programs could get away
with ignoring the issue completely.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

James Kanze

unread,
May 2, 2001, 2:20:14 PM5/2/01
to
Wil Evers wrote:

> I'd say this comparison isn't entirely fair. Guaranteed load-time
> initialization is a platform feature, not a language feature.

It's part of the Java language specification. HOW the implementation
achieves it is platform dependant, but it is a requirement.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Wil Evers

unread,
May 3, 2001, 5:36:06 AM5/3/01
to
In article <3AEFC30A...@dresdner-bank.com>, James Kanze wrote:

> Wil Evers wrote:
>
>> I'd say this comparison isn't entirely fair. Guaranteed load-time
>> initialization is a platform feature, not a language feature.
>
> It's part of the Java language specification. HOW the implementation
> achieves it is platform dependant, but it is a requirement.

That depends on what you call a platform. I'd say the Java language runs
on just one platform: the Java Virtual Machine. The JVM spec is quite
clear on what must happen when a class is loaded, including extensive
support for dynamic initialization. Because of this, the corresponding
Java language requirement is trivial to fulfill.

In contrast, the C++ language standard, which targets many different
platforms, cannot rely on that same level of platform support.

- Wil

--
Wil Evers, DOOSYS IT Consultants, Utrecht, Holland


[Wil underscore Evers at doosys dot com]

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
May 4, 2001, 9:07:28 AM5/4/01
to
Wil Evers wrote:

> In article <3AEFC30A...@dresdner-bank.com>, James Kanze wrote:

> > Wil Evers wrote:

> >> I'd say this comparison isn't entirely fair. Guaranteed
> >> load-time initialization is a platform feature, not a language
> >> feature.

> > It's part of the Java language specification. HOW the
> > implementation achieves it is platform dependant, but it is a
> > requirement.

> That depends on what you call a platform. I'd say the Java language
> runs on just one platform: the Java Virtual Machine.

That's not true. There are native code compilers for Java, Jet or
Natural Bridge, for example. You can use Java without a virtual
machine. The implementation still has to behave as if it is using
load-time initialization.

> The JVM spec is quite clear on what must happen when a class is
> loaded, including extensive support for dynamic initialization.
> Because of this, the corresponding Java language requirement is
> trivial to fulfill.

> In contrast, the C++ language standard, which targets many different
> platforms, cannot rely on that same level of platform support.

The initial point concerned order of initialization, I think. Java is
not the first to specify this; I remember seeing it specified in
Modula-2, for example. It is implementable on every platform I can
think of.

It isn't implementable with the traditional Unix linker, however.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Robert Klemme

unread,
May 4, 2001, 2:46:35 PM5/4/01
to

James Kanze schrieb:


> It's relatively easy to construct cases in Java where you access a
> variable before it is correctly initialized. While Java protects you
> in this particular case (which isn't hard to avoid in C++, either), it
> regularly calls member functions on unconstructed objects, since a
> call from the base class constructor resolves to a function in the
> derived class. (And this is not an abstract consideration. I can't
> count the times I've needed to add code in a member function to verify
> that initialization has occured. Mostly in classes derived from
> Swing, where the constructors seem to call many functions.)

one more reason to not do too much in a constructor. but, yes, i agree.

> IMHO, you always have to worry about writing correct code. There are
> some features of Java, like garbage collection, which allow you to
> write less code without it being incorrect, but globally, I find that
> Java creates more problems than it solves when the goal is to write
> correct code.

disagree. java makes a lot things easier than C++ which improved
programmer productivity: no multiple inheritance, no virtual or private
inheritance, interfaces, no preprocessor, only one source per class
etc...

> The very link model you mention works against you most
> of the time, because you are never quite sure what classes the client
> code is actually loading;

how come that you are so unsure about this? we do not have this
problem.

> your application doesn't have one version,
> but one version per class, which results in more potential versions
> than you'll ever be able to test.

that's not true: put them in a jar and then you have the same as a
library (more precisely a dll) in C++.

robert


--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestraße 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert...@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Chris Uzdavinis

unread,
May 4, 2001, 8:23:40 PM5/4/01
to
Robert Klemme <robert...@myview.de> writes:

> disagree. java makes a lot things easier than C++ which improved
> programmer productivity: no multiple inheritance, no virtual or
> private inheritance, interfaces, no preprocessor, only one source
> per class etc...

Any feature that is misused will be tricky/ugly/difficult. Multiple
inheritance is no exception. But it seems to you have arrived at a
conclusion (and expect others to simply agree) that it's inherently
more difficult to program in C++ using multiple inheritance than
without it.

I must disagree. There are situations where MI is the best (or at
least a very good) solution. Please explain how needing feature X and
not having it available makes it easier to program.

> > The very link model you mention works against you most
> > of the time, because you are never quite sure what classes the client
> > code is actually loading;
>
> how come that you are so unsure about this? we do not have this
> problem.

Therefore it does not exist?


[snip]

--
Chris

Wil Evers

unread,
May 5, 2001, 8:00:56 AM5/5/01
to
In article <3AF2696E...@dresdner-bank.com>, James Kanze wrote:

> Wil Evers wrote:
>
>> I'd say the Java language
>> runs on just one platform: the Java Virtual Machine.
>
> That's not true. There are native code compilers for Java, Jet or
> Natural Bridge, for example. You can use Java without a virtual
> machine. The implementation still has to behave as if it is using
> load-time initialization.

More generally, while there is no requirement that the implementation
actually uses a Java byte code interpreter at run-time, it has to behave as
if it is using the JVM. Hence my statement. But that's just a quibble, of
course.

[snip]

>> In contrast, the C++ language standard, which targets many different
>> platforms, cannot rely on that same level of platform support.
>
> The initial point concerned order of initialization, I think. Java is
> not the first to specify this; I remember seeing it specified in
> Modula-2, for example. It is implementable on every platform I can
> think of.

So let's go back to that original point: how do we build a library that
supplies an object which is always available from the constructors and
destructors of other classes using this library? (Assuming no circular
dependencies between these objects, of course.)

The nifty counter idiom (a la ios_base::Init) is more or less portable, and
it almost always works. However, it can only be used for objects of
classes that are purposely designed to be used in this way, it may cause
nasty surprises that can only be understood by a true expert, and it can
take a considerable performance hit at program startup and shutdown.

The alternative is to use load-time initialization, which means the library
writer must somehow seize control of the loading and unloading order at
program startup and shutdown. I *think* I know how to get away with this
under Win32, provided the library is shipped as a DLL.

However, for the UNIX platforms I'm familiar with, I have not succeeded in
getting this right without dictating the linker command line order. Better
platform-level support would certainly help here.

- Wil

--
Wil Evers, DOOSYS IT Consultants, Utrecht, Holland
[Wil underscore Evers at doosys dot com]

James Kanze

unread,
May 7, 2001, 12:55:39 PM5/7/01
to
Wil Evers wrote:

> So let's go back to that original point: how do we build a library
> that supplies an object which is always available from the
> constructors and destructors of other classes using this library?
> (Assuming no circular dependencies between these objects, of
> course.)

Simple. The linker builds a dependancy graph, and orders the
initialization according to it. This is the way Modula-2 systems
worked. It's a bit more complicated in C++, because it isn't always
obvious to the compiler what uses what. But I suspect that most of
the complication would be in the specification, and I think part of it
is already present in the wording about potentially-evaluated
expressions, see 3.2/2; a static object is used if it is referred to
in a potentially evaluated expression.

Of course, with statically initialized pointers and such, this would
probably give less guarantees than in the case of Modula. I think, in
fact, that this was the reason why it wasn't considered.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

James Kanze

unread,
May 7, 2001, 12:58:15 PM5/7/01
to
Robert Klemme wrote:

> James Kanze schrieb:
> > It's relatively easy to construct cases in Java where you access a
> > variable before it is correctly initialized. While Java protects
> > you in this particular case (which isn't hard to avoid in C++,
> > either), it regularly calls member functions on unconstructed
> > objects, since a call from the base class constructor resolves to
> > a function in the derived class. (And this is not an abstract
> > consideration. I can't count the times I've needed to add code in
> > a member function to verify that initialization has occured.
> > Mostly in classes derived from Swing, where the constructors seem
> > to call many functions.)

> one more reason to not do too much in a constructor. but, yes, i agree.

> > IMHO, you always have to worry about writing correct code. There
> > are some features of Java, like garbage collection, which allow
> > you to write less code without it being incorrect, but globally, I
> > find that Java creates more problems than it solves when the goal
> > is to write correct code.

> disagree.

You disagree that I find that Java creates more problems?

Both languages create a lot of problems. In the environments I've
worked in, I've found that in general, there are work-arounds for the
C++ problems: smart pointers instead of garbage collection, etc. The
work-arounds do entail more work, and represent a real cost that could
be avoided by a better language. The problem with Java is that in
some cases, cases essential IMHO for robust programming (like
programming by contract), Java not only doesn't support the idiom
directly, it doesn't allow you to work around the problem. (In other
cases, I think it is just a case of the "standard idioms" not yet
having been found, or at least not being widely known.)

> java makes a lot things easier than C++ which improved
> programmer productivity: no multiple inheritance, no virtual or
> private inheritance, interfaces, no preprocessor, only one source
> per class etc...

With the exception of the preprocessor, everything you mention reduces
productivity in Java:

- Java has multiple inheritance. The only thing it doesn't have is
the possibility of verifying the contract in the base class (which
it calls an interface), because an interface cannot contain code.

- What is the problem with virtual inheritance? If you aren't sure,
just use it systematically, and you won't have any problems.
Ditto the type of inheritance: always public, and while you will
probably loose some compiler verifications, it should also work.

> > The very link model you mention works against you most of the
> > time, because you are never quite sure what classes the client
> > code is actually loading;

> how come that you are so unsure about this? we do not have this
> problem.

You don't have the problem, or you haven't recognized it yet? We
didn't actually recognize that there could be a problem until we
started deployment, with updates and different versions. Note that
the same problem can (and does) occur in C++ with DLLs.

> > your application doesn't have one version, but one version per
> > class, which results in more potential versions than you'll ever
> > be able to test.

> that's not true: put them in a jar and then you have the same as a
> library (more precisely a dll) in C++.

Only if you seal the package. And even then, only at the package
level.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Robert Klemme

unread,
May 8, 2001, 6:26:55 PM5/8/01
to

Chris Uzdavinis schrieb:

> Any feature that is misused will be tricky/ugly/difficult. Multiple
> inheritance is no exception. But it seems to you have arrived at a
> conclusion (and expect others to simply agree) that it's inherently
> more difficult to program in C++ using multiple inheritance than
> without it.

not just multiple inheritance. the difference between productivity with
Java and C++ does not only come from the lack of multiple inheritance.

> I must disagree. There are situations where MI is the best (or at
> least a very good) solution. Please explain how needing feature X and
> not having it available makes it easier to program.

putting the question that way it's obvious that it's easier if you can
use a feature that you need instead of writing a workaround. however:

i intended to say something slightly different. maybe this has not
become clear enough. first of all let me state that i view this from a
project perspective and not from an individual coder's perspective. how
do they differ? if i'm alone i can code along the lines i am used to
and that i know. because it's just me, the code will be all the same
style. in a project this is diefferent.

these things make life harder:

- having a lot of options to solve some problem makes it likely that
there are different implementations within a project around. this makes
understanding more difficult and thus maintenance.

- a language, that lacks features, which have to be implemented on a
per project or per company basis. (i'm thinking here of gc, interfaces
etc.) this makes it necessary that you enforce a certain idiom or style
manually as opposed to beeing forced by the language.

- features that are inherently dangerous like the C preprocessor.
doing textual substitutions ignoring any context can be make code really
ugly. i regard this as a major drawback which outweights the advantages
of the CPP.

- if for many problems / tasks there are too many ways to do it: method
binding, inheritance types (who needs private inheritance?), string
representation (char* and std::string) etc.

the single thing i am really missing in Java is destructors. but for
certain reasons it's quite difficult to implement them correctly. (for
those who are interested in the background of this look at the
documentation of Object.finalize() to get an impression.)

> > > The very link model you mention works against you most
> > > of the time, because you are never quite sure what classes the client
> > > code is actually loading;

> > how come that you are so unsure about this? we do not have this
> > problem.

> Therefore it does not exist?

exactly. :-) at least, not for us.

all in all i think this is not a subject that can be easily resolved:
there are so many problem domains and so many personal preferences that
it's hardly possible to state on a general basis language X is better /
more productive / ... than language Y. maybe i made too strong a point
in the beginning. but at least from my experience i can say that Java
is quite a lot more productive.

but one thing i can say for sure: these discussions are productive!

regards

robert

--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestraße 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert...@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Robert Klemme

unread,
May 8, 2001, 6:27:55 PM5/8/01
to

James Kanze schrieb:


> You disagree that I find that Java creates more problems?

yes.

> Both languages create a lot of problems.

then we probably better skip programming and have less problems on the
whole? :-))

> In the environments I've
> worked in, I've found that in general, there are work-arounds for the
> C++ problems: smart pointers instead of garbage collection, etc. The
> work-arounds do entail more work, and represent a real cost that could
> be avoided by a better language.

exactly! and it's not only more coding work but as well more making
sure conventions are met by co workers etc.

> The problem with Java is that in
> some cases, cases essential IMHO for robust programming (like
> programming by contract), Java not only doesn't support the idiom
> directly, it doesn't allow you to work around the problem.

please excluse my ignorance, but what feature of the java language
prevents you from programming by contract. or are you saying that there
is only eiffel that supports this?

> (In other
> cases, I think it is just a case of the "standard idioms" not yet
> having been found, or at least not being widely known.)

hm. could you give examples. currently i do not have an idea what
exactly you are allude to.

> With the exception of the preprocessor, everything you mention reduces
> productivity in Java:
>
> - Java has multiple inheritance. The only thing it doesn't have is
> the possibility of verifying the contract in the base class (which
> it calls an interface), because an interface cannot contain code.

this is true. you can of course create centralized code that does this
verification.

> - What is the problem with virtual inheritance? If you aren't sure,
> just use it systematically, and you won't have any problems.
> Ditto the type of inheritance: always public, and while you will
> probably loose some compiler verifications, it should also work.

of course it will. but my point is that YOU have to impose this
restriction. if you are a development manager or a project leader you
have to make sure, everybody works this way. this is not effective.

> You don't have the problem, or you haven't recognized it yet? We
> didn't actually recognize that there could be a problem until we
> started deployment, with updates and different versions. Note that
> the same problem can (and does) occur in C++ with DLLs.

so there's the same solutions to this and it is not a disadvantage of
the Java language.

[one version per class]


> Only if you seal the package.

sealing helps against making modifications to the jar. but normally
this should not occur unless what you are delilvering are beans. but
with these it's meant to be that way. of course you cannot be sure,
which classes are used when some customer is tampering with the deployed
software. but who would expect that?

> And even then, only at the package
> level.

no. it's totally up to you how much you put into the jar. it can be a
whole application or it can be a package or something in between. so
this boils down to a problem that you have with all languages:
management of versions and deployment.

regards

robert


--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestraße 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert...@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Chris Uzdavinis

unread,
May 9, 2001, 1:14:33 PM5/9/01
to
Robert Klemme <robert...@myview.de> writes:

> Chris Uzdavinis schrieb:
> > Any feature that is misused will be tricky/ugly/difficult. Multiple
> > inheritance is no exception. But it seems to you have arrived at a
> > conclusion (and expect others to simply agree) that it's inherently
> > more difficult to program in C++ using multiple inheritance than
> > without it.
>
> not just multiple inheritance. the difference between productivity with
> Java and C++ does not only come from the lack of multiple inheritance.

I agree. I'm more productive with C++ for more reasons than just its
support for multiple inheritance. :)

[snip]


> i intended to say something slightly different. maybe this has not
> become clear enough. first of all let me state that i view this from a
> project perspective and not from an individual coder's perspective. how
> do they differ? if i'm alone i can code along the lines i am used to
> and that i know. because it's just me, the code will be all the same
> style. in a project this is diefferent.

Ok, but when the language has already made the choice for you,
wouldn't it seem likely that for some (perhaps many) problems, the
language supports the wrong feature? What to do then? If it's just
style, that is one thing, but if it's a matter of capability, that's
certainly another.

> these things make life harder:
>
> - having a lot of options to solve some problem makes it likely that
> there are different implementations within a project around. this makes
> understanding more difficult and thus maintenance.

Again, simplification of a problem (by reducing choices to one) may
make it "easier" to know how you can tackle the problem, but it
certainly does not make it easier to necessarily do it correctly.
When there is no choice in your approach, you just have to hope that
what actually is supported is "good enough" for the job. Personally,
I like having a choice. When I find that one method fails, at least I
have the hope of finding an alternative that may work. When there is
only one choice and it is unsatisfactory, then what?


> - a language, that lacks features, which have to be implemented on a
> per project or per company basis. (i'm thinking here of gc, interfaces
> etc.) this makes it necessary that you enforce a certain idiom or style
> manually as opposed to beeing forced by the language.

Same again, choice is freedom, and in a way it's also insurance.
Wasn't Java's original container library burdened with synchronization
locks that rendered them such high overhead that for many cases they
were almost unusable?

> - features that are inherently dangerous like the C preprocessor.
> doing textual substitutions ignoring any context can be make code really
> ugly. i regard this as a major drawback which outweights the advantages
> of the CPP.

Any plaintext file can be preprocessed by anything, even processed by
perl scripts. That a preprocessor is available in the language
specification doesn't change this fact. Most C++ code that I see
doesn't make use of macros except for portability and conditional
compilation. When macros are used, it's for the code-generation
properties rather than "inlining" functions. Again, it certainly can
be abused, but it certainly doesn't have to be.

> - if for many problems / tasks there are too many ways to do it: method
> binding, inheritance types (who needs private inheritance?), string
> representation (char* and std::string) etc.

I suppose those who don't need private inheritance are those who don't
understand it.

Still, for char* I agree it's low level and can be dangerous when not
used correctly and carefully. That's why we have the string class.

> > > > The very link model you mention works against you most
> > > > of the time, because you are never quite sure what classes the client
> > > > code is actually loading;
>
> > > how come that you are so unsure about this? we do not have this
> > > problem.
>
> > Therefore it does not exist?
>
> exactly. :-) at least, not for us.

... or it hasn't hit you yet, perhaps.

> all in all i think this is not a subject that can be easily resolved:
> there are so many problem domains and so many personal preferences that
> it's hardly possible to state on a general basis language X is better /
> more productive / ... than language Y. maybe i made too strong a point
> in the beginning. but at least from my experience i can say that Java
> is quite a lot more productive.

It's a tradeoff of simplicity and expressiveness and options. I like
options, because I can have it *exactly* my way without compromise.

> but one thing i can say for sure: these discussions are productive!

Yes, they are producing large files on my hard drive. :)

--
Chris

James Dennett

unread,
May 9, 2001, 5:37:24 PM5/9/01
to
Robert Klemme wrote:
>
> James Kanze schrieb:
>
> > The problem with Java is that in
> > some cases, cases essential IMHO for robust programming (like
> > programming by contract), Java not only doesn't support the idiom
> > directly, it doesn't allow you to work around the problem.
>
> please excluse my ignorance, but what feature of the java language
> prevents you from programming by contract.

I think it's clear that James is pointing out that Java interfaces
cannot enfore pre- and post-conditions, because they cannot include
*any* code. In C++ an interface can be implemented as a class
with pubic non-virtual methods which check pre- and post-conditions
etc., forwarding to private virtual methods where needed. In Java
you can only inherit from one such safe interface (class) -- real
Java "interfaces" are no more than a collection of method
signatures and constants, they cannot even attempt to ensure
that meanings are followed.

-- James Dennett

Martin Aupperle

unread,
May 10, 2001, 12:35:59 PM5/10/01
to
On 4 May 2001 14:46:35 -0400, Robert Klemme <robert...@myview.de>
wrote:

>disagree. java makes a lot things easier than C++ which improved
>programmer productivity: no multiple inheritance, no virtual or private
>inheritance, interfaces, no preprocessor, only one source per class
>etc...
>

Then simply don't use these things in C++!

Please explain why *having* things can be worse than not having them.

And, BTW, you forgot the mostly mentioned argument: pointers.

------------------------------------------------
Martin Aupperle
MikeAlpha@NoSpam_csi.com
(remove NoSpam_)

Nicola Musatti

unread,
May 10, 2001, 9:53:32 PM5/10/01
to
I would say that one problem with Java is that it does remove features
that may be dangerous if misused, without really acknowledging how the
same features can prove advantageous if well used. That is, alternative
features that are both safe and as powerful as those that are removed,
are simply not available.

The preprocessor may be very useful to provide different, alternative
versions of a single application. Runtime conditionals are an inferior
option.

Multiple inheritance is very useful to let a class provide different
personalities by combining interfaces and mixins. Explicitly dispatching
to multiple delegates may be more elastic, but is also more complicated.

Garbage collection solves most pointer related problems, but at the cost
of forbidding objects with value semantics and destructors, two
techniques that already helped limit pointer problems in C++ over, say,
C. Again, the other uses that such features have in C++ are not replaced
in Java.

What is true is that Java is certainly easier to learn than C++, so that
beginners appear to become more productive sooner, but as to the quality
of their code, well, I don't think that Java (nor any other language)
can force you to design your programs well. On the other hand my
impression is that Java makes it more difficult to leverage the skills
of the small set of top notch programmers that are indispensible to the
success of any serious project.

Best regards,
Nicola Musatti

Nicola Musatti

unread,
May 10, 2001, 10:35:49 PM5/10/01
to
Isn't it about time that modules (aka packages, in the ADA sense) are
added to C++? I have the impression that the C++ concept of a linker is
somewhat schizoid: at times it requires to stick to early 1970's
technology at others it expects rather sophisticated solutions.

A module feature that allowed a more sophisticated interface
specification than header files and prevented circular dependencies
would solve many practical problems and very probably also speed up
average compilation speed.

Best regards,
Nicola Musatti

Robert Klemme

unread,
May 11, 2001, 3:15:07 PM5/11/01
to

Nicola Musatti schrieb:


> That is, alternative
> features that are both safe and as powerful as those that are removed,
> are simply not available.

i think there is a inherent conflict between powerful and safe. i
personally have come to acknowledge the advantages of restriction; in
german we have a saying "less is more". and this is true! information
hiding is one of the major features of any modularized concept - be it
in a procedural language (module et. al.) or be it in an oo language.
the challenge is to expose the right set of methods to the outside world
and not to expose as much as possible.

> The preprocessor may be very useful to provide different, alternative
> versions of a single application. Runtime conditionals are an inferior
> option.

the java solution to this is to use different classes for the
implementation of this and configure the correct class in some
configuration. i find this superior to including a lot of variants in
the same source.

> What is true is that Java is certainly easier to learn than C++, so that
> beginners appear to become more productive sooner, but as to the quality
> of their code, well, I don't think that Java (nor any other language)
> can force you to design your programs well.

this is true. but since we are confronted with new libraries, new
functionality etc. all the time we are all beginners most of the time.
do not underestimate this aspect.

> On the other hand my
> impression is that Java makes it more difficult to leverage the skills
> of the small set of top notch programmers that are indispensible to the
> success of any serious project.

i think even profession developers have enough ways to show their
proficiency in java.

regards

robert

--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestraße 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert...@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Robert Klemme

unread,
May 11, 2001, 3:18:02 PM5/11/01
to

Chris Uzdavinis schrieb:

> > not just multiple inheritance. the difference between productivity with
> > Java and C++ does not only come from the lack of multiple inheritance.
>
> I agree. I'm more productive with C++ for more reasons than just its
> support for multiple inheritance. :)

:-)))))))

> Ok, but when the language has already made the choice for you,
> wouldn't it seem likely that for some (perhaps many) problems, the
> language supports the wrong feature? What to do then? If it's just
> style, that is one thing, but if it's a matter of capability, that's
> certainly another.

well, i do not think that java lacks so many capabilities. i would
agree to everybody who says it's slow and it is not optimal suited for
GUI applications because of its performance.

> Again, simplification of a problem (by reducing choices to one) may
> make it "easier" to know how you can tackle the problem, but it
> certainly does not make it easier to necessarily do it correctly.
> When there is no choice in your approach, you just have to hope that
> what actually is supported is "good enough" for the job. Personally,
> I like having a choice.

this is exactly the point: PERSONALLY you like it. but from a project
leader's perspective i do prefer a reduced set of choices. and, believe
me: there are still enough choices in java left. but they lie more in
the design domain and not in the area of implementation details.

> When there is
> only one choice and it is unsatisfactory, then what?

then it's unsatisfactory, period. i observe that people are too
pretentious and quarrel with a lot of things that they think could be
better. with this they spend so much time worrying instead of just
doing what it needs to get the word done.

> Any plaintext file can be preprocessed by anything, even processed by
> perl scripts.

of course. but the fact, that the C preprocessor is run over the source
code anyway encourages people to use it extensively.

> I suppose those who don't need private inheritance are those who don't
> understand it.

well, then we should start another thread in which you can explain that
to me. or post some pointers to articles about that. all i can say is
that MY observations of private inheritance were due to lazyness. the
real solution to the problem should have been delegation.

> Still, for char* I agree it's low level and can be dangerous when not
> used correctly and carefully. That's why we have the string class.

... and unfortunately we do not have the string class only. intermixing
this in one application leads to ugly code and memory leaks as well.
*sigh*

> > exactly. :-) at least, not for us.
>
> ... or it hasn't hit you yet, perhaps.

it has - in the meantime. :-))

> It's a tradeoff of simplicity and expressiveness and options. I like
> options, because I can have it *exactly* my way without compromise.

yes, that's ok as long as you are alone. but with team development i
must clearly say this is a no option. not everybody can have it his /
her way. this way things don't work out.

> > but one thing i can say for sure: these discussions are productive!
> Yes, they are producing large files on my hard drive. :)

that's why i write these lenghty answers. :-))

bye

robert

--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestraße 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert...@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Robert Klemme

unread,
May 11, 2001, 3:19:07 PM5/11/01
to

James Dennett schrieb:


> I think it's clear that James is pointing out that Java interfaces
> cannot enfore pre- and post-conditions, because they cannot include
> *any* code. In C++ an interface can be implemented as a class
> with pubic non-virtual methods which check pre- and post-conditions
> etc., forwarding to private virtual methods where needed.

ok, thank you. but even with C++ this is a workaround. shouldn't we
then all switch over to eiffel?

robert

--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestraße 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert...@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Robert Klemme

unread,
May 11, 2001, 3:19:40 PM5/11/01
to

Martin Aupperle schrieb:


> Then simply don't use these things in C++!

this is not as simple as you say: in a bigger project this can generate
significant efforts to enforce the "not use" policies.

> Please explain why *having* things can be worse than not having them.

because they can be abused.

> And, BTW, you forgot the mostly mentioned argument: pointers.

thanks for reminding us. :-)

robert

--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestraße 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert...@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Dennett

unread,
May 13, 2001, 8:21:37 AM5/13/01
to
Robert Klemme wrote:
>
> James Dennett schrieb:
> > I think it's clear that James is pointing out that Java interfaces
> > cannot enfore pre- and post-conditions, because they cannot include
> > *any* code. In C++ an interface can be implemented as a class
> > with pubic non-virtual methods which check pre- and post-conditions
> > etc., forwarding to private virtual methods where needed.
>
> ok, thank you. but even with C++ this is a workaround. shouldn't we
> then all switch over to eiffel?

Or think about whether the C++ workaround (as I agree that
is a fair description) could be extended to give more of
the full DbC behaviour of Eiffel? On the DbC support scale,
C++ fits between Java and Eiffel.

-- James Dennett

Gerhard Menzl

unread,
May 14, 2001, 3:10:04 PM5/14/01
to
Robert Klemme wrote:

> > I suppose those who don't need private inheritance are those who
> > don't understand it.
>
> well, then we should start another thread in which you can explain
> that to me. or post some pointers to articles about that. all i can
> say is that MY observations of private inheritance were due to
> lazyness. the real solution to the problem should have been
> delegation.

Private inheritance is appropriate whenever a class is supposed to
present an exclusive interface to selected clients rather than to the
general public. A very good example is the GoF State pattern:

class State;

class AbstractSubject
{
public:
virtual void ChangeState (State* newState) = 0;

// other manipulation functions reserved for the state classes
};

class State
{
public:
virtual void Handle (AbstractSubject* subject) = 0;
};

// classes derived from State

class ConcreteSubject : private AbstractSubject
{
public:
void Request ()
{
currentState->Handle (this);
}

private:
virtual void ChangeState (State* newState)
{
currentState = newState;
}

State* currentState;
};

// constructors, pre- and postcondition checks etc. omitted
// for the sake of brevity

You don't want external clients of ConcreteSubject to change the state
willy-nilly, but subclasses of State are required to do so. Private
inheritance solves this very elegantly. Please show me how you would
solve this using delegation.

See also James Newkirk's paper "Private Interface" at:

http://www.objectmentor.com/publications/privateInterface.pdf

Gerhard Menzl

Gerhard Menzl

unread,
May 14, 2001, 3:11:59 PM5/14/01
to
Robert Klemme wrote:

> > Please explain why *having* things can be worse than not having
> > them.
>
> because they can be abused.

In my observation, inheritance is about the most abused feature in OO
programming. Would you agree to abolish it?

Gerhard Menzl

Matt Seitz

unread,
May 14, 2001, 11:49:36 PM5/14/01
to

"Gerhard Menzl" <gerhar...@sea.ericsson.se> wrote in message
news:3AFF9473...@sea.ericsson.se...

> Robert Klemme wrote:
>
> > > Please explain why *having* things can be worse than not having
> > > them.
> >
> > because they can be abused.
>
> In my observation, inheritance is about the most abused feature in OO
> programming. Would you agree to abolish it?

You are correct, the criteria should be whether the "feature" does more harm
than good and whether a better replacement exists.

Kevin Cline

unread,
May 15, 2001, 9:29:38 AM5/15/01
to
Gerhard Menzl <gerhar...@sea.ericsson.se> writes:

> Private inheritance is appropriate whenever a class is supposed to
> present an exclusive interface to selected clients rather than to the

> general public....


>
> class ConcreteSubject : private AbstractSubject
> {
> public:
> void Request ()
> {
> currentState->Handle (this);
> }
>
> private:
> virtual void ChangeState (State* newState)
> {
> currentState = newState;
> }
>
> State* currentState;
> };
>

> You don't want external clients of ConcreteSubject to change the state
> willy-nilly, but subclasses of State are required to do so. Private
> inheritance solves this very elegantly. Please show me how you would
> solve this using delegation.

class ConcreteSubject {
private:
struct AbstractSubjectImpl : public AbstractSubject {
State* currentState;

virtual void ChangeState(State* newState) {
currentState = newState;
}
}

AbstractSubjectImpl subjectImpl;

public:
void Request() {
subjectImpl.currentState->Handle(subjectImpl);
}
};

--
Kevin Cline

David Bradley

unread,
May 15, 2001, 12:26:13 PM5/15/01
to
Martin Aupperle wrote:
> Then simply don't use these things in C++!
>
> Please explain why *having* things can be worse than not having them.

>From a language standpoint, adding a feature generally adds mounds of
complexity. It's hard to understand the full impact and implications of
adding a feature to a language at the time you are adding it. This
results in compilers being more complex, and compiler writers more prone
to getting things wrong.

>From a developer's standpoint, take MI for instance. While you may
choose to not use it, you might have libraries and such that use it and
force you to deal with the issues in your use of the libraries. Of
course you could choose not to use such libraries.

I'm not necessarily arguing that MI shouldn't be in the language. Just
that any feature, especially one that impacts the object model would
have a lot of issues known and unknown and that the benefit would have
to be substantial IMO to justify it.

Read some of the papers on the language Self to find out what they found
results from adding features to a language.

Gerhard Menzl

unread,
May 16, 2001, 5:56:28 PM5/16/01
to
Kevin Cline wrote:

> > You don't want external clients of ConcreteSubject to change the
> > state willy-nilly, but subclasses of State are required to do so.
> > Private inheritance solves this very elegantly. Please show me how
> > you would solve this using delegation.
>
> class ConcreteSubject {
> private:
> struct AbstractSubjectImpl : public AbstractSubject {
> State* currentState;
>
> virtual void ChangeState(State* newState) {
> currentState = newState;
> }
> }
>
> AbstractSubjectImpl subjectImpl;
>
> public:
> void Request() {
> subjectImpl.currentState->Handle(subjectImpl);
> }
> };

So you have replaced private inheritance by a private nested class that
inherits publicly. Apart from increasing the level-of-indirection count
and making the code harder to understand, what does this buy you? Why
faking a feature that's built right into the language?

Robert Klemme argued that private inheritance is usually a sign of
lazyness, and that delegation should be used instead. I demonstrated how
private inheritance can be superior to delegation. That there is a more
convoluted way that among other things involves delegation does not
invalidate my argument.

Gerhard Menzl

0 new messages