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

Warning

0 views
Skip to first unread message

Leigh Johnston

unread,
Mar 3, 2010, 2:01:41 PM3/3/10
to
Warning: contact with this newsgroup can result in exposure to toxic
opinions the treatment of which involves the use of copious amounts of
thinking for yourself.

Alf P. Steinbach

unread,
Mar 3, 2010, 3:10:24 PM3/3/10
to
* Leigh Johnston:

> Warning: contact with this newsgroup can result in exposure to toxic
> opinions the treatment of which involves the use of copious amounts of
> thinking for yourself.

:-)

IMHO you're absolutely right -- but it applies to any newsgroup!

On the other hand, ..., well, wait, I'm not opening that can.

But on the third and gripping hand, while the opinion that I think triggered
that blast, "don't derive from concrete classes", may not be the world's best
advice, it is a practice that works for some kinds of problems. For example,
original COM was built on something very similar to that idea, "don't expose
derivation from concrete classes to client code". But I think that even that
more limited idea was shown to be too drastic, when COM+ did away with it. :-)


Cheers,

- Alf

Leigh Johnston

unread,
Mar 3, 2010, 3:52:35 PM3/3/10
to

"Alf P. Steinbach" <al...@start.no> wrote in message
news:hmmfnk$i2s$1...@news.eternal-september.org...

COM does not mandate that policy; it says nothing on how a particular server
class is implemented, i.e. a server class could be implemented by a number
of classes related through inheritance. All that is exposed to the client
is the abstract interface (a collection of public pure virtual functions).

/Leigh

Alf P. Steinbach

unread,
Mar 3, 2010, 3:58:42 PM3/3/10
to
* Leigh Johnston:

>
>
> "Alf P. Steinbach" <al...@start.no> wrote in message
> news:hmmfnk$i2s$1...@news.eternal-september.org...
>> * Leigh Johnston:
>>> Warning: contact with this newsgroup can result in exposure to toxic
>>> opinions the treatment of which involves the use of copious amounts
>>> of thinking for yourself.
>>
>> :-)
>>
>> IMHO you're absolutely right -- but it applies to any newsgroup!
>>
>> On the other hand, ..., well, wait, I'm not opening that can.
>>
>> But on the third and gripping hand, while the opinion that I think
>> triggered that blast, "don't derive from concrete classes", may not be
>> the world's best advice, it is a practice that works for some kinds of
>> problems. For example, original COM was built on something very
>> similar to that idea, "don't expose derivation from concrete classes
>> to client code". But I think that even that more limited idea was
>> shown to be too drastic, when COM+ did away with it. :-)
>>
>
> COM does not mandate that policy;

Well, you then continue saying that it does:


> it says nothing on how a particular
> server class is implemented, i.e. a server class could be implemented by
> a number of classes related through inheritance. All that is exposed to
> the client is the abstract interface (a collection of public pure
> virtual functions).

So, that's a self-contradiction.

Which means that readers must think for themselves.


Cheers,

- Alf

Leigh Johnston

unread,
Mar 3, 2010, 4:10:11 PM3/3/10
to

"Alf P. Steinbach" <al...@start.no> wrote in message

news:hmmii4$5jk$1...@news.eternal-september.org...

You said original COM has built on the idea that you don't derive from
concrete classes and I was contradicting that: you can have a class
hierarchy that implements a particular COM interface, i.e. there doesn't
need to be a one-to-one mapping between a COM interface and a single server
implementation class.

/Leigh

Ian Collins

unread,
Mar 3, 2010, 4:09:03 PM3/3/10
to
Alf P. Steinbach wrote:
> * Leigh Johnston:
>> Warning: contact with this newsgroup can result in exposure to toxic
>> opinions the treatment of which involves the use of copious amounts of
>> thinking for yourself.
>
> :-)
>
> IMHO you're absolutely right -- but it applies to any newsgroup!
>
> On the other hand, ..., well, wait, I'm not opening that can.
>
> But on the third and gripping hand, while the opinion that I think
> triggered that blast, "don't derive from concrete classes", may not be
> the world's best advice, it is a practice that works for some kinds of
> problems.

Maybe "avoid deriving publicly form concrete classes" would be better
advice? It certainly applies to standard containers.

--
Ian Collins

Leigh Johnston

unread,
Mar 3, 2010, 4:12:27 PM3/3/10
to

"Ian Collins" <ian-...@hotmail.com> wrote in message
news:7v81ij...@mid.individual.net...

Not true, take a look at http://i42.co.uk/stuff/mutable_set.htm

/Leigh

Ian Collins

unread,
Mar 3, 2010, 4:35:42 PM3/3/10
to

A counter example doesn't negate a general guideline. There will always
be cases where a guideline doesn't apply because a guideline is only a
recommendation, not a rule. I would use private derivation for the
example in TC++PL, the interface class is changing the behaviour of
std::vector, so it should only expose interfaces that comply with the
change (consider what would happen if the user mixed at() with [] access).

I still maintain that "avoid deriving publicly from concrete classes" is
a valid guideline. Any advice that saves the novice unnecessary grief
should be welcome and I've seen nasty bugs caused by improper use of
pointers to concrete base classes.

--
Ian Collins

Leigh Johnston

unread,
Mar 3, 2010, 4:44:16 PM3/3/10
to

"Ian Collins" <ian-...@hotmail.com> wrote in message

news:7v834i...@mid.individual.net...

I am sorry but this is just absolute garbage; there is absolutely nothing
wrong with deriving publicly or otherwise from concrete classes. The
standard containers are not designed to be derived from if you consider that
they do not have a virtual destructor but I have given an example (as has
Stroustrup) where this is ok.

The "is-a" relationship does not dictate that base classes must be abstract
and a so called guideline which dictates otherwise is simply ill conceived
bullshit. Just because you have seen "nasty bugs" is mostly irrelevant.
This newsgroup really does contain some drivel to which you have just added
to.

/Leigh

Alf P. Steinbach

unread,
Mar 3, 2010, 4:48:40 PM3/3/10
to

Yes, except for lack of attention to detail you're violently agreeing with me. :-)

Note what you quoted. It's not the same as your paraphrase.


Cheers,

- Alf

Ian Collins

unread,
Mar 3, 2010, 5:01:35 PM3/3/10
to

No, it isn't. Consider a trivial example based on the cited TC++PL
reference:

#include <iostream>
#include <vector>

class Vector : public std::vector<int> {
int lb;
public:
Vector( int low, int high )
: std::vector<int>(high-low+1), lb(low) {}

int& operator[](int i) { return std::vector<int>::operator[](i-lb); }
};

template <typename T> void f( const std::vector<T>& v ) {
std::cout << v[1] << std::endl;
}

int main() {
Vector vec(1,10);

vec[1] = 42;

std::cout << vec.at(1) << std::endl;
f( vec );
}

> The standard containers are not designed to be derived from if
> you consider that they do not have a virtual destructor but I have given
> an example (as has Stroustrup) where this is ok.

As you can see, it is not OK. A Vector is *not* a std::vector<int>.
Vector adapts the behaviour of std::vector<int>, so it can't be used as
one unless it restricts the public interface.

--
Ian Collins

Leigh Johnston

unread,
Mar 3, 2010, 5:13:44 PM3/3/10
to

"Ian Collins" <ian-...@hotmail.com> wrote in message

news:7v84l3...@mid.individual.net...

More garbage. Vector "is-a" std::vector<int> is true. This is basic object
orientation. I am getting tired of this - get a fucking clue please. A
derived class does not have to hide the public interface of a base class for
the "is-a" relationship to hold true. at() is part of vector's interface.
Vector's operator[] hides vector's operator[] in this example but this does
not stop you from using vector's operator[] if you wanted to. Read
http://en.wikipedia.org/wiki/Liskov_substitution_principle

/Leigh

Leigh Johnston

unread,
Mar 3, 2010, 5:24:51 PM3/3/10
to

"Leigh Johnston" <le...@i42.co.uk> wrote in message
news:CeSdnWcoLsyFQhPW...@giganews.com...

Or to put it another way the "is-a" relationship holds true as modifying a
Vector object via the std::vector interface does not invalidate Vector's
invariant. Hiding a base class interface function with a derived class
function is a side issue.

/Leigh

Ian Collins

unread,
Mar 3, 2010, 5:33:25 PM3/3/10
to
Leigh Johnston wrote:
>
> Or to put it another way the "is-a" relationship holds true as modifying
> a Vector object via the std::vector interface does not invalidate
> Vector's invariant.

It does:

vec.at(1) = 33;

std::cout << vec[1] << std::endl;

--
Ian Collins

Leigh Johnston

unread,
Mar 3, 2010, 5:42:12 PM3/3/10
to

>> Or to put it another way the "is-a" relationship holds true as modifying
>> a Vector object via the std::vector interface does not invalidate
>> Vector's invariant.
>
> It does:
>
> vec.at(1) = 33;
>
> std::cout << vec[1] << std::endl;
>
> --

It doesn't. 1 has a different meaning for the two calls. Whilst Vector's
operator[] hides std::vector's operator[] which has different semantics it
doesn't prevent Vector "is-a" std::vector relationship. If Vector "is-a"
relationship didn't hold then static_cast<std::vector<int>&>(vec)[1]
wouldn't work.

/Leigh

Leigh Johnston

unread,
Mar 3, 2010, 5:48:35 PM3/3/10
to

"Leigh Johnston" <le...@i42.co.uk> wrote in message

news:XNCdnRbfh8xbeBPW...@giganews.com...

(Assuming vec.std::vector<int>::operator int[](1) was valid of course).

Like I said, modifying a Vector object via the std::vector interface does
not break Vector's invariant as Vector "is-a" std::vector.

Leigh Johnston

unread,
Mar 3, 2010, 6:51:37 PM3/3/10
to

"Ian Collins" <ian-...@hotmail.com> wrote in message

news:7v86go...@mid.individual.net...

Vector as it stands does not make much sense and should also provide an at()
but even then you cannot do a straight substitution is parameter values
would have different meanings so it is not a particularly good example I
admit, however "is-a" still holds, you can pass a reference to a Vector to a
function which takes a std::vector reference and it still works.

/Leigh

Ian Collins

unread,
Mar 3, 2010, 6:54:31 PM3/3/10
to
Leigh Johnston wrote:
>
>
> "Ian Collins" <ian-...@hotmail.com> wrote in message
> news:7v86go...@mid.individual.net...
>> Leigh Johnston wrote:
>>>
>>> Or to put it another way the "is-a" relationship holds true as
>>> modifying a Vector object via the std::vector interface does not
>>> invalidate Vector's invariant.
>>
>> It does:
>>
>> vec.at(1) = 33;
>>
>> std::cout << vec[1] << std::endl;
>
> Vector as it stands does not make much sense and should also provide an
> at() but even then you cannot do a straight substitution is parameter
> values would have different meanings so it is not a particularly good
> example I admit, however "is-a" still holds, you can pass a reference to
> a Vector to a function which takes a std::vector reference and it still
> works.

I agree. I had overlooked Vector's operator[] hiding rather than
overloading std::vector's.

It's nice to see a reasoned response without expletives and personal
insults :)

--
Ian Collins

Anthony Delroy

unread,
Mar 3, 2010, 8:57:22 PM3/3/10
to
> >>> Maybe "avoid deriving publicly form concrete classes" would be better
> >>> advice?  It certainly applies to standard containers.
>
> > A counter example doesn't negate a general guideline.  There will always
> > be cases where a guideline doesn't apply because a guideline is only a
> > recommendation, not a rule.  I would use private derivation for the
> > example in TC++PL, the interface class is changing the behaviour of
> > std::vector, so it should only expose interfaces that comply with the
> > change (consider what would happen if the user mixed at() with [] access).
>
> > I still maintain that "avoid deriving publicly from concrete classes" is a
> > valid guideline.  Any advice that saves the novice unnecessary grief
> > should be welcome and I've seen nasty bugs caused by improper use of
> > pointers to concrete base classes.
>
> I am sorry but this is just absolute garbage; there is absolutely nothing
> wrong with deriving publicly or otherwise from concrete classes.  The
> standard containers are not designed to be derived from if you consider that
> they do not have a virtual destructor but I have given an example (as has
> Stroustrup) where this is ok.
>
> The "is-a" relationship does not dictate that base classes must be abstract
> and a so called guideline which dictates otherwise is simply ill conceived
> bullshit.  Just because you have seen "nasty bugs" is mostly irrelevant.
> This newsgroup really does contain some drivel to which you have just added
> to.
>
> /Leigh

Quick note of agreement. I'm all-too-regularly dismayed at how much
time and effort some people spend either writing half-baked containers
or using STL containers in an awkward, verbose and/or error-prone
fashion simply because they'd read or been told they shouldn't derive
from them to customise the interface to intended usage. Avoiding
customisation typically introduces far more bugs and confusion,
lowering productivity and flexibility. The number of times I've seen
someone proceed to allocate a derived object on the heap and free it
through a base-class pointer is minute in comparison.

Guidelines can be good, but it's important to do things simply and
directly where it works. Similar issues with struct + public data vs
classes + accessor functions: you only bother with the latter where
it's useful, shared across files etc.. Or providing function
implementation out of line. Lots of little things like this, taking
experience to know where to draw the line. A "safe" guideline for
beginners isn't necessarily safer if it forces those beginners to use
a long-winded and more confusing workaround to achieve the same
functionality....

Cheers,
Tony

Michael Doubez

unread,
Mar 4, 2010, 3:32:46 AM3/4/10
to

IMHO "don't derive from concrete class" is a poor wording. I prefer
"inherit an interface, not an implementation" (IIRC adapted from
Gamma&GoF).

IMNSHO inheriting from a concrete class is perfectly valid when you
only want to add to the interface of an object - after all, it is part
of the 3 fundamental OOP rules.

--
Michael

Leigh Johnston

unread,
Mar 4, 2010, 5:42:01 AM3/4/10
to

"Michael Doubez" <michael...@free.fr> wrote in message
news:845cf7d6-779a-4cc8...@o3g2000yqb.googlegroups.com...

Inheriting from a concrete class to provide additional state and/or logic is
also fine. Inheritance is fine, period.

/Leigh

Michael Doubez

unread,
Mar 4, 2010, 6:08:54 AM3/4/10
to
On 4 mar, 11:42, "Leigh Johnston" <le...@i42.co.uk> wrote:
> "Michael Doubez" <michael.dou...@free.fr> wrote in message

Other languages felt the need to distinguish between "extends" and
"implements"
or between "class" and "interface" (and add some constraints along
the way). Inheritance in C++ (which fulfill both roles) is not as
straightforward.

In this regard, IMO C++ inherited from C's way of thinking "let the
programmer be in control"; and it is the programmer's responsibility
to enforce the design is correct.

--
Michael

James Kanze

unread,
Mar 4, 2010, 1:28:30 PM3/4/10
to
On Mar 3, 9:09 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> Alf P. Steinbach wrote:

[...]


> > But on the third and gripping hand, while the opinion that I
> > think triggered that blast, "don't derive from concrete
> > classes", may not be the world's best advice, it is a
> > practice that works for some kinds of problems.

> Maybe "avoid deriving publicly form concrete classes" would be
> better advice? It certainly applies to standard containers.

I don't know. I haven't seen the thread that goes into that
topic in detail---I rather thought the reaction concerned not
making virtual functions public. But whatever: a fairly long
time ago, Scott Meyers recommended not deriving from concrete
classes, or at least, not deriving from classes with data
members. Because of the problems correctly implementing
assignment, I think. In practice, on the other hand, the
template method pattern will often require derivation from a
class with data members, and it's a fairly well established
pattern. And since we've since more or less learned that
assignment and polymorphism don't mix well, classes using the
template method pattern will normally block assignment, rather
than try to implement it.

At any rate, I don't really think of it as a general rule,
although except when using the template method pattern, it's not
something that you'd probably want to do too often. (Note too
that it's been a while since I've heard anyone argue for this
rule. I don't know what Scott's position concerning it is
today.)

--
James Kanze

James Kanze

unread,
Mar 4, 2010, 1:37:57 PM3/4/10
to
On Mar 4, 8:32 am, Michael Doubez <michael.dou...@free.fr> wrote:
> On 3 mar, 21:10, "Alf P. Steinbach" <al...@start.no> wrote:
> > * Leigh Johnston:

> IMHO "don't derive from concrete class" is a poor wording. I prefer


> "inherit an interface, not an implementation" (IIRC adapted from
> Gamma&GoF).

> IMNSHO inheriting from a concrete class is perfectly valid
> when you only want to add to the interface of an object -
> after all, it is part of the 3 fundamental OOP rules.

Before arguing against the rule, it would be interesting to see
who is proposing it, and why. To date, the only thing I've seen
recently is a mention that Herb Sutter cites it. Until I've
seen why it's being recommended, I can't really argue one way or
the other. (I haven't actuall seen anyone propose it since
about 1995, but I haven't seen everything. Still, I would like
to know what is wrong with something like:

class TemplateBase
{
private:
virtual void customizationFunction();
// with a default implemenation
};

A class using the template method pattern for customization,
but which provides defaults for all of the customization, seems
like a classical example of a case where a concrete class is
actuall designed to be used as a base class (with public
inheritance).

Deriving from classes which weren't designed to be bases (such
as the standard containers) is generally a bad idea. But the
key to whether you should derive from a class or not isn't
whether it is concrete or not; it's whether it was designed to
be used as a base class or not.

--
James Kanze

Michael Doubez

unread,
Mar 5, 2010, 4:26:43 AM3/5/10
to
On 4 mar, 19:37, James Kanze <james.ka...@gmail.com> wrote:
> On Mar 4, 8:32 am, Michael Doubez <michael.dou...@free.fr> wrote:
>
> > On 3 mar, 21:10, "Alf P. Steinbach" <al...@start.no> wrote:
> > > * Leigh Johnston:
> > IMHO "don't derive from concrete class" is a poor wording. I prefer
> > "inherit an interface, not an implementation" (IIRC adapted from
> > Gamma&GoF).
> > IMNSHO inheriting from a concrete class is perfectly valid
> > when you only want to add to the interface of an object -
> > after all, it is part of the 3 fundamental OOP rules.
>
> Before arguing against the rule, it would be interesting to see
> who is proposing it, and why.

I cannot remember who stated them, it dates to my academics:
"A computer language is object-oriented if they support the three
fundamental features: polymorphism, inheritance, and encapsulation."

Inheritance in the OOP sense, i.e. (arguably) to reuse a class
implementation in order to *add* to its interface (not modifying its
internals, that's polymorphism).

>  To date, the only thing I've seen
> recently is a mention that Herb Sutter cites it.  Until I've
> seen why it's being recommended, I can't really argue one way or
> the other.  (I haven't actuall seen anyone propose it since
> about 1995, but I haven't seen everything.  Still, I would like
> to know what is wrong with something like:
>
>         class TemplateBase
>         {
>         private:
>                 virtual void customizationFunction();
>                                         // with a default implemenation
>         };
>
> A class using the template method pattern for customization,
> but which provides defaults for all of the customization, seems
> like a classical example of a case where a concrete class is
> actuall designed to be used as a base class (with public
> inheritance).

IMHO, part of the misunderstanding stems from the fact that in C++,
polymorphism is /usually/ performed through inheritance.

As a consequence, in C++ a class can inherit from another for both
reasons: reusing code (of the base classe) and create a polymorphic
implementation.

Whether it is a good thing or not is IMO what is (should be) debated
here; should a virtual function from a base class be implemented ?
Separating the concern, with your example we could write:

class TemplateBaseIsPolymorphic
{
private:
virtual void customizationFunction()=0;
};

class TemplateBase: TemplateBaseIsPolymorphic
{
private:
virtual void customizationFunction()
{
// default implementation
}
};

From the C++ language point of view, this doesn't add a lot and
personally I prefer the original example.

> Deriving from classes which weren't designed to be bases (such
> as the standard containers) is generally a bad idea.

That's because, IMO the standard containers usually have a complete
interface and there is no need to.

> But the
> key to whether you should derive from a class or not isn't
> whether it is concrete or not; it's whether it was designed to
> be used as a base class or not.

My point exactly.

--
Michael

Leigh Johnston

unread,
Mar 5, 2010, 5:25:36 AM3/5/10
to

"Michael Doubez" <michael...@free.fr> wrote in message

news:cdb20f88-8668-4092...@j27g2000yqn.googlegroups.com...

The examples I gave where for the case where an interface needs to be
augmented but you use the word "usually" which is fine: "usually" is not
"always".

>
>> But the
>> key to whether you should derive from a class or not isn't
>> whether it is concrete or not; it's whether it was designed to
>> be used as a base class or not.
>
> My point exactly.
>
> --

A class does not have to be abstract to be usable as a base class.

/Leigh

Juha Nieminen

unread,
Mar 5, 2010, 8:19:38 AM3/5/10
to
Michael Doubez wrote:
> Inheritance in the OOP sense, i.e. (arguably) to reuse a class
> implementation in order to *add* to its interface (not modifying its
> internals, that's polymorphism).

One could say that there are two schools of thought about inheritance:
The "extends" faction and the "specializes" faction (although they are
not necessarily mutually exclusive). There's a subtle difference between
the two ways of thinking about inheritance.

In the "extends" school of thought inheritance is seen as taking a
class and adding more functionality to it. It's also related to code
reuse: If two classes have common functionality, the common
functionality can be grouped into a common base class, and then the two
classes can inherit from it (so, in effect, the two classes are now
extending the base class functionality in two different ways, while
having the common functionality in one place, thus avoiding code
repetition). Thus when you inherit you could say "DerivedClass extends
BaseClass".

The "specializes" school of thought is more related to object-oriented
design. This is where the concept of the "is-a" relationship comes from.
Here a class is a concept, and there's a scale of abstraction between
concepts: Some concepts are more abstract and generic, while others are
more concrete and specialized. For example, in a GUI framework you could
have a class named "Widget", and several classes derived from it, eg.
"Button" and "Label". In this case "Widget" is a more generic and
abstract concept, while "Button" and "Label" are more concrete concepts.
In other words, they are Widget specializations. Thus one can say that
"Button is-a Widget" and "Label is-a Widget". However, Button is *not* a
Label. What this means in practice is that wherever an object of type
Widget is expected, an object of type Button or Label can be given
instead (because a Button *is* a Widget, as well as a Label *is* a
Widget). However, if a Button is expected, a Label cannot given to it
(because a Label is *not* a Button). Thus when you inherit you could say
"DerivedClass specializes BaseClass" (ie. creates a more concrete
concept from it).

The "specializes" school of thought is not mutually exclusive with the
"extends" one. One could say that the latter is just a side-effect of
the former, and could be used (or "abused") for that purpose.

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

James Kanze

unread,
Mar 5, 2010, 1:32:41 PM3/5/10
to
On 5 Mar, 09:26, Michael Doubez <michael.dou...@free.fr> wrote:
> On 4 mar, 19:37, James Kanze <james.ka...@gmail.com> wrote:
> > On Mar 4, 8:32 am, Michael Doubez <michael.dou...@free.fr> wrote:

> > > On 3 mar, 21:10, "Alf P. Steinbach" <al...@start.no> wrote:
> > > > * Leigh Johnston:
> > > IMHO "don't derive from concrete class" is a poor wording.
> > > I prefer "inherit an interface, not an implementation"
> > > (IIRC adapted from Gamma&GoF).
> > > IMNSHO inheriting from a concrete class is perfectly valid
> > > when you only want to add to the interface of an object -
> > > after all, it is part of the 3 fundamental OOP rules.

> > Before arguing against the rule, it would be interesting to
> > see who is proposing it, and why.

> I cannot remember who stated them, it dates to my academics:
> "A computer language is object-oriented if they support the
> three fundamental features: polymorphism, inheritance, and
> encapsulation."

Which doesn't really address the question: C++ does support
those three fundamental features, so it is object-oriented.
(But it's not only object-oriented; it supports other things as
well.) And those three features say nothing about deriving from
a concrete class---the template method pattern was frequent long
before the GoF named it; as far as I know, it was always
considered good OO practice. And if the base class in the
template method pattern provides a default implementation, it is
concrete.

> Inheritance in the OOP sense, i.e. (arguably) to reuse a class
> implementation in order to *add* to its interface (not
> modifying its internals, that's polymorphism).

> > To date, the only thing I've seen recently is a mention that
> > Herb Sutter cites it. Until I've seen why it's being
> > recommended, I can't really argue one way or the other. (I
> > haven't actuall seen anyone propose it since about 1995, but
> > I haven't seen everything. Still, I would like to know what
> > is wrong with something like:

> > class TemplateBase
> > {
> > private:
> > virtual void customizationFunction();
> > // with a default implemenation
> > };

> > A class using the template method pattern for customization,
> > but which provides defaults for all of the customization,
> > seems like a classical example of a case where a concrete
> > class is actuall designed to be used as a base class (with
> > public inheritance).

> IMHO, part of the misunderstanding stems from the fact that in
> C++, polymorphism is /usually/ performed through inheritance.

As it is in many modern OO languages. Static typing isn't
without advantages.

> As a consequence, in C++ a class can inherit from another for
> both reasons: reusing code (of the base classe) and create a
> polymorphic implementation.

> Whether it is a good thing or not is IMO what is (should be)
> debated here; should a virtual function from a base class be
> implemented ? Separating the concern, with your example we
> could write:

> class TemplateBaseIsPolymorphic
> {
> private:
> virtual void customizationFunction()=0;
>
> };

> class TemplateBase: TemplateBaseIsPolymorphic
> {
> private:
> virtual void customizationFunction()
> {
> // default implementation
>
> }
> };

> From the C++ language point of view, this doesn't add a lot
> and personally I prefer the original example.

Yes. Separation of concerns is a good principle, but there are
times that it can be taken too far. (Actually, which of the
above is preferrable depends on the context. What if it were:

class TemplateBase
{
virtual void customizationFunction() = 0;
};

class DefaultTemplate : public TemplateBase
{
virtual void customizationFunction()
{
// default implementation...
}
};

.)

> > Deriving from classes which weren't designed to be bases
> > (such as the standard containers) is generally a bad idea.

> That's because, IMO the standard containers usually have a
> complete interface and there is no need to.

Also, maybe. But my rule holds: deriving from a class which was
not designed to be used as a base will generally cause problems
in the long run, and should generall be avoided. (There are
exceptions, and I have no problems with people deriving in order
to provide a few special constructors; e.g. to create a fully
filled const vector.)

--
James Kanze

Michael Doubez

unread,
Mar 8, 2010, 4:27:44 AM3/8/10
to
On 5 mar, 11:25, "Leigh Johnston" <le...@i42.co.uk> wrote:
> "Michael Doubez" <michael.dou...@free.fr> wrote in message

> news:cdb20f88-8668-4092...@j27g2000yqn.googlegroups.com...
> > On 4 mar, 19:37, James Kanze <james.ka...@gmail.com> wrote:
[snip]

> >> Deriving from classes which weren't designed to be bases (such
> >> as the standard containers) is generally a bad idea.
>
> > That's because, IMO the standard containers usually have a complete
> > interface and there is no need to.
>
> The examples I gave where for the case where an interface needs to be
> augmented but you use the word "usually" which is fine: "usually" is not
> "always".

But the corollary is that is seldom useful or a good design decision
to inherit from them. A complete interface means that functions or
composition should be used; AFAIS there are three cases:
- the extended part is stateless: a function should be used
- the extended part keeps associated state:
* the extended class should be somewhat notified of modification
but the base class is not designed that way and composition should be
used (I exclude an external notify modification system)
* the extended class doesn't need to be notified, both
information should be composed as a pair in another structure
* the extended structure exploits the internal of the container:
this is not portable, even across the same version of the compiler.

I don't say that such cases never *exists*, but IMHO they should
require an exceptionally good justification (such as "can't do it
another way and it will be strongly encapsulated").

> >> But the
> >> key to whether you should derive from a class or not isn't
> >> whether it is concrete or not; it's whether it was designed to
> >> be used as a base class or not.
>
> > My point exactly.
>

> A class does not have to be abstract to be usable as a base class.

It doesn't but it is IMO a very narrow usage of inheritance in C++; I
can't see I have never seen it (or done it).

But, one strives to provide a complete interface without compromising
encapsulation, doesn't he.

--
Michael

Michael Doubez

unread,
Mar 8, 2010, 4:57:36 AM3/8/10
to

I hear what you say but I have a gut feeling that the is-a/has-a
system is very good for tuition of concept thinking but rarely scale
in practice.
When people think of is-a, they tend to speak about polymorphism -
i.e. the object should respond to a given interface.
We can see the failing in the case of the circle which is an ellipsis
but doesn't share the interface. We you say an animal is-a mammal, you
expect him to have some attributes not to respond to an archetypal
mammal form.
In the end, you have to determine the minimal interface that doesn't
break LSP.
In don't say it doesn't work (it certainly work in Small-Talk), it is
just that it doesn't scale so well (even in small talk, there is an
extensive usage of the fallback function).

IMHO the concept system should be orthogonal with inheritance (as it
is with standard containers) and perhaps relabel is-a into act-as.

Taking the GUI framework example, IMO "Widget" is another word for
"Stuff that belong to the framework"; which is kin to "lets give use a
base class to manipulate them generically". Which means that, as I see
it, a widget is an interface to polymorphic behavior.

I have in mind a badly designed GUI library (fltk IIRC) where
everything had been put into the /Widget/ base class (the actions
callback, the label ...) and subclasses used them or not depending on
the specialization.

--
Michael

Leigh Johnston

unread,
Mar 8, 2010, 6:01:46 AM3/8/10
to

"Michael Doubez" <michael...@free.fr> wrote in message

news:d962d8ed-d69e-4b5f...@e7g2000yqf.googlegroups.com...


> On 5 mar, 11:25, "Leigh Johnston" <le...@i42.co.uk> wrote:
>> "Michael Doubez" <michael.dou...@free.fr> wrote in message
>> news:cdb20f88-8668-4092...@j27g2000yqn.googlegroups.com...
>> > On 4 mar, 19:37, James Kanze <james.ka...@gmail.com> wrote:
> [snip]
>> >> Deriving from classes which weren't designed to be bases (such
>> >> as the standard containers) is generally a bad idea.
>>
>> > That's because, IMO the standard containers usually have a complete
>> > interface and there is no need to.
>>
>> The examples I gave where for the case where an interface needs to be
>> augmented but you use the word "usually" which is fine: "usually" is not
>> "always".
>
> But the corollary is that is seldom useful or a good design decision
> to inherit from them. A complete interface means that functions or
> composition should be used; AFAIS there are three cases:
> - the extended part is stateless: a function should be used
> - the extended part keeps associated state:
> * the extended class should be somewhat notified of modification
> but the base class is not designed that way and composition should be
> used (I exclude an external notify modification system)
> * the extended class doesn't need to be notified, both
> information should be composed as a pair in another structure
> * the extended structure exploits the internal of the container:
> this is not portable, even across the same version of the compiler.
>

Garbage. The "is-a" relationship is well defined and perfectly fine. There
are problems such as a derived class modifying a base class's protected
member variables possible breaking base's invariant but as the old saying
goes guns don't kill people, people kill people. It is perfectly fine for a
derived class to modify a base class via a base class's protected/public
member functions. It is perfectly fine for a derived class to be "notified"
of changes or behavioural sequence points via virtual functions. It is
perfectly fine for a base class to provide a default implementation for a
virtual function that the derived class override can choose to call.

/Leigh

Michael Doubez

unread,
Mar 8, 2010, 6:39:48 AM3/8/10
to

Really ?
A minimal complete interface is IMO an essential value for general
purpose class design (I am not talking about classes implementing
specific use cases).

> The "is-a" relationship is well defined

I am curious to hear your definition.

> and perfectly fine.

I find it ambiguous: it depends on what you mean by "is".

In fact, I find it useful only in defining what is-not (i.e. what
should be composed and not inherited).

> [snip]

--
Michael

Leigh Johnston

unread,
Mar 8, 2010, 7:48:42 AM3/8/10
to

"Michael Doubez" <michael...@free.fr> wrote in message

news:bffc3535-8ad3-4816...@j27g2000yqn.googlegroups.com...

Example of "is-a":

struct widget
{
colour background;
virtual void draw(device_context& dc) const
{
dc.fill_rect(client_rect(), background);
}
colour get_background() const { return background; }
};

struct label : widget
{
virtual void draw(device_context& dc) const
{
widget::draw(dc); // erases background in background colour
dc.draw_text(0, 0, get_background() ^ -1, label_text()); // draw text in
inverted colour
}
};

label "is-a" widget, i.e. it inherits a widget's ability to fill in its
background and this behaviour is optional (label does not have to call
widget::draw()). label also inherits widget's background colour and can
query it for use in its own drawing code.

"is-a" is related to LSP:

struct window
{
std::vector<widget*> widgets;
device_context dc;
void draw()
{
for (auto i = widgets.begin(); i != widgets.end(); ++i)
i->draw(dc);
}
}

i.e. if LSP is adhered to then a label can be passed to any function which
accepts a widget reference/pointer. This is the essence of the "is-a"
relationship.

/Leigh

Leigh Johnston

unread,
Mar 8, 2010, 7:56:18 AM3/8/10
to

> struct window
> {
> std::vector<widget*> widgets;
> device_context dc;
> void draw()
> {
> for (auto i = widgets.begin(); i != widgets.end(); ++i)
> i->draw(dc);
> }
> }
>

I meant (*i)->draw(dc); of course.

/Leigh

Michael Doubez

unread,
Mar 8, 2010, 9:36:14 AM3/8/10
to
> Example of "is-a":
>
> struct widget
> {
>   colour background;
>   virtual void draw(device_context& dc) const
>   {
>     dc.fill_rect(client_rect(), background);
>   }
>   colour get_background() const { return background; }
>
> };
>
> struct label : widget
> {
>   virtual void draw(device_context& dc) const
>   {
>     widget::draw(dc); // erases background in background colour
>     dc.draw_text(0, 0, get_background() ^ -1, label_text()); // draw text in
> inverted colour
>   }
> };
>
> label "is-a" widget, i.e. it inherits a widget's ability to fill in its
> background and this behaviour is optional (label does not have to call
> widget::draw()).  label also inherits widget's background colour and can
> query it for use in its own drawing code.

If I have a Spacer widget that doesn't draw anything, the background
member is useless.

And the name widget (WIndow gaDGET) is not really a thing, it is more
a base class for elements contained within a window. To me, it looks
like something you are forced into by strong typing rather than a
design decision.

> "is-a" is related to LSP:
>
> struct window
> {
>   std::vector<widget*> widgets;
>   device_context dc;
>   void draw()
>   {
>     for (auto i = widgets.begin(); i != widgets.end(); ++i)
>       i->draw(dc);
>   }
> }
>
> i.e. if LSP is adhered to then a label can be passed to any function which
> accepts a widget reference/pointer.  This is the essence of the "is-a"
> relationship.

Well, is-a yields a correct program only if it preserves LSP. Although
there are some cases where LSP is not preserved: if I make Integer and
String subtypes of AdditiveType, Integer addition is symmetric but
String addition/concatenation is not although math tells us that '+'
is reserved for symmetric operations.

From the examples you gave, I see that, for you, is-a is thought in
terms of interface and polymorphism, not in terms of subtyping.

Now, if I have a class Mammal:
class Mammal
{
public:
Mammal(unsigned nb_breast):nb_breast(nb_breast){}

unsigned nbBreast()const{ return nb_breast; };
protected:
unsigned nb_breast;
};

If I define cat is-a mammal:
class Cat: public Mammal
{
public:
enum Type{ /* type of cat */};

Cat(Type type): Mammal(catType2NbBreast(type)){}

void mastectomy(unsigned nb_breast_removed)
{
assert( nb_breast_removed <= nb_breast);
nb_breast -= nb_breast_removed;
}
};

Here, I have a is-a relationship without talking about LSP or
polymorphism.

As I said elsewhere, the fact that C++ implements (dynamic)
polymorphism in terms of inheritance doesn't help. Well, it couldn't
do it another way, now, could it ?

--
Michael

Leigh Johnston

unread,
Mar 8, 2010, 9:49:43 AM3/8/10
to

"Michael Doubez" <michael...@free.fr> wrote in message

news:64baf247-ed93-400a...@d2g2000yqa.googlegroups.com...

Your example is just an example of ordinary derivation, I use derivation for
non-polymorphic classes also. Both the "is-a" relationship and LSP do not
require polymorphism to be valid I never said they did, I just happened to
give an example which was polymorphic.

"is-a" relationship holds true if LSP holds true. Your example does not
violate LSP, I can pass a Cat to a function requiring an Mammal reference
and calling the nbBreast() member function will work.

/Leigh

Leigh Johnston

unread,
Mar 8, 2010, 10:01:40 AM3/8/10
to

"Michael Doubez" <michael...@free.fr> wrote in message

news:64baf247-ed93-400a...@d2g2000yqa.googlegroups.com...

If you want an example of where I use an "is-a" relationship which does not
involve polymorphism and polymorphic interfaces then take a look at xml.h in
my XML library http://www.i42.co.uk/stuff/NoFussXML.zip

The only virtual function in the entire library is the virtual destructor of
the XML node base class and I suspect we can both agree that virtual dtors
are special cases. So you are incorrect to say that I do not use "is-a" for
subtyping.

/Leigh

Michael Doubez

unread,
Mar 8, 2010, 10:23:10 AM3/8/10
to
> Your example is just an example of ordinary derivation, I use derivation for
> non-polymorphic classes also.  Both the "is-a" relationship and LSP do not
> require polymorphism to be valid I never said they did, I just happened to
> give an example which was polymorphic.

LSP does concern polymorphism otherwise it is useless. I merely gave
an example of is-a relationship without polymorphism to show LSP is
not part of "the essence of 'is-a' relationship".

> "is-a" relationship holds true if LSP holds true.  Your example does not
> violate LSP, I can pass a Cat to a function requiring an Mammal reference
> and calling the nbBreast() member function will work.

Yes but LSP is not involved in any way in my example.

I think we have lost the trail of the discussion somewhere. My claim
was that is-a relationship is ambiguous and is usually assimilated to
polymorphism - which it is not.

And you are proving me right: the first example you give is pure
polymorphic behavior and you define it in relation to LSP.

Unless you are claiming that a is-a relationship is necessarily
polymorphic; in which case I will ask: isn't my example a is-a
relationship ?

--
Michael

Leigh Johnston

unread,
Mar 8, 2010, 10:27:38 AM3/8/10
to

"Michael Doubez" <michael...@free.fr> wrote in message

news:0c4c83bc-bed1-459d...@q15g2000yqj.googlegroups.com...

See my other reply, "is-a" does not have to be polymorphic modulo virtual
destructors.

/Leigh

Michael Doubez

unread,
Mar 8, 2010, 10:35:05 AM3/8/10
to
On 8 mar, 16:01, "Leigh Johnston" <le...@i42.co.uk> wrote:
> "Michael Doubez" <michael.dou...@free.fr> wrote in message
[snip]

> If you want an example of where I use an "is-a" relationship which does not
> involve polymorphism and polymorphic interfaces then take a look at xml.h in
> my XML libraryhttp://www.i42.co.uk/stuff/NoFussXML.zip

>
> The only virtual function in the entire library is the virtual destructor of
> the XML node base class and I suspect we can both agree that virtual dtors
> are special cases.  So you are incorrect to say that I do not use "is-a" for
> subtyping.

I said no such thing. I said that polymorphism (subtyping) involves is-
a (at least in C++ for dynamic polymorphism) but the reverse is not
true.

--
Michael

Leigh Johnston

unread,
Mar 8, 2010, 10:49:57 AM3/8/10
to

"Michael Doubez" <michael...@free.fr> wrote in message

news:302b6b32-025c-4dc4...@d2g2000yqa.googlegroups.com...

I think we are in agreement as I am no longer sure what the hell we are
arguing about - "is-a" does not have to involve polymorphism I agree. I am
starting to hate this newsgroup.

/Leigh

Michael Doubez

unread,
Mar 8, 2010, 10:52:03 AM3/8/10
to
On 8 mar, 16:27, "Leigh Johnston" <le...@i42.co.uk> wrote:
> "Michael Doubez" <michael.dou...@free.fr> wrote in message
[snip]

> > I think we have lost the trail of the discussion somewhere. My claim
> > was that is-a relationship is ambiguous and is usually assimilated to
> > polymorphism - which it is not.
>
> > And you are proving me right: the first example you give is pure
> > polymorphic behavior and you define it in relation to LSP.
>
> > Unless you are claiming that a is-a relationship is necessarily
> > polymorphic; in which case I will ask: isn't my example a is-a
> > relationship ?
>
> See my other reply, "is-a" does not have to be polymorphic modulo virtual
> destructors.

is-a doesn't have to be polymorphic if you don't invoke the destructor
from the base class; albeit I agree the choices are limited in C++ for
some designs.

Since we seem to agree that is-a relationship is not necessarily
invoking polymorphic behavior (if we ever disagreed on that, the
thread is quite long and tangled now), let's get back to the point you
labeled as garbage:
even though is-a is a specialization, I think you will agree that in
fact, we are extending the interface and not modifying its internals
(that's polymorphism).

In this case, my claim is that this usage of inheritance is a valid
design case of inheriting a concrete class.

And I also said that it is rarely done in practice; I have not read
your XML library but I assume you are proving me wrong on that point.

--
Michael

Michael Doubez

unread,
Mar 8, 2010, 10:55:04 AM3/8/10
to
On 8 mar, 16:49, "Leigh Johnston" <le...@i42.co.uk> wrote:
> "Michael Doubez" <michael.dou...@free.fr> wrote in message
>
> news:302b6b32-025c-4dc4...@d2g2000yqa.googlegroups.com...
>
>
>
> > On 8 mar, 16:01, "Leigh Johnston" <le...@i42.co.uk> wrote:
> >> "Michael Doubez" <michael.dou...@free.fr> wrote in message
> > [snip]
> >> If you want an example of where I use an "is-a" relationship which does
> >> not
> >> involve polymorphism and polymorphic interfaces then take a look at xml.h
> >> in
> >> my XML libraryhttp://www.i42.co.uk/stuff/NoFussXML.zip
>
> >> The only virtual function in the entire library is the virtual destructor
> >> of
> >> the XML node base class and I suspect we can both agree that virtual
> >> dtors
> >> are special cases.  So you are incorrect to say that I do not use "is-a"
> >> for
> >> subtyping.
>
> > I said no such thing. I said that polymorphism (subtyping) involves is-
> > a (at least in C++ for dynamic polymorphism) but the reverse is not
> > true.
>
>
> I think we are in agreement as I am no longer sure what the hell we are
> arguing about - "is-a" does not have to involve polymorphism I agree.  I am
> starting to hate this newsgroup.

It keeps us hot on these chilly days.

And you know that programmers are a bickering lot :)

--
Michael

Juha Nieminen

unread,
Mar 8, 2010, 4:13:40 PM3/8/10
to
Michael Doubez wrote:
> I hear what you say but I have a gut feeling that the is-a/has-a
> system is very good for tuition of concept thinking but rarely scale
> in practice.

I wouldn't say "rarely". It may be true that *bad design* often
results in programs where the "is-a" school of design just doesn't work,
and that there are tons of examples of such bad design out there.
However, that doesn't mean that the "is-a" concept is flawed in itself.
It just has to be properly implemented.

Besides the "widget"-style design that is extremely common in GUI
frameworks, another good example of "is-a" polymorphism is the C++
streams: A function may take a reference to eg. a std::ostream, and you
can give it std::cout, an std::ofstream or an std::ostringstream, and it
will work nicely. This is object-oriented design in action.

There may be situations where this design doesn't work but, after all,
OOD is not a silver bullet.

> I have in mind a badly designed GUI library (fltk IIRC) where
> everything had been put into the /Widget/ base class (the actions
> callback, the label ...) and subclasses used them or not depending on
> the specialization.

This is usually where multiple inheritance (even if in a limited form)
steps in to aid in a better overall design. For example a button may be
both a widget and a mouse event listener. Hence a button can be given to
any code expecting a widget, or one expecting a mouse event listener
because the button is both.

(For some unfathomable reason many programmers, even experienced ones,
have this misconception that multiple inheritance is a bad thing, and
will go to great lengths to argue how you don't need it, how they don't
use it, and how "interfaces" and "protocols" aren't *really* multiple
inheritance (even though they are). I don't understand this attitude.
Multiple inheritance is a very nice way of simplifying your design and
making it more logical and modular.)

Michael Doubez

unread,
Mar 9, 2010, 4:10:07 AM3/9/10
to
On 8 mar, 22:13, Juha Nieminen <nos...@thanks.invalid> wrote:
> Michael Doubez wrote:
> > I hear what you say but I have a gut feeling that the is-a/has-a
> > system is very good for tuition of concept thinking but rarely scale
> > in practice.
>
>   I wouldn't say "rarely". It may be true that *bad design* often
> results in programs where the "is-a" school of design just doesn't work,
> and that there are tons of examples of such bad design out there.
> However, that doesn't mean that the "is-a" concept is flawed in itself.
> It just has to be properly implemented.

I wouldn't go as far as say it is flawed, it just that IMO is-a has
just the dose of familiarity that makes it dangerous: it lets you
believe you can think in terms of concept and map them with the
programming language.
This sometimes work (and quite well) but IMO it is incidental to the
fact that the programmer says 'is-a' and thinks 'has-the-same-
interface/common attribute/...'

>   Besides the "widget"-style design that is extremely common in GUI
> frameworks, another good example of "is-a" polymorphism is the C++
> streams: A function may take a reference to eg. a std::ostream, and you
> can give it std::cout, an std::ofstream or an std::ostringstream, and it
> will work nicely. This is object-oriented design in action.
>
>   There may be situations where this design doesn't work but, after all,
> OOD is not a silver bullet.

The widget example is symptomatic: a widget has not reality, it is a
design artifact to compose and abstract GUI elements. If I take (with
caution) the definition on wikipedia: "The defining characteristic of
a widget is to provide a single interaction point for the direct
manipulation of a given kind of data. In other words, widgets are
basic visual building blocks which, combined in an application, hold
all the data processed by the application and the available
interactions on this data."

In a message passing programming language, there is no necessity for
GUI elements to share a common base type, they only need to implement
a common interface (spacial placement, observable, GUI event
observer ...)

[snip]

--
Michael

Juha Nieminen

unread,
Mar 9, 2010, 6:58:31 PM3/9/10
to
Michael Doubez wrote:
> I wouldn't go as far as say it is flawed, it just that IMO is-a has
> just the dose of familiarity that makes it dangerous: it lets you
> believe you can think in terms of concept and map them with the
> programming language.

You just have to understand what "is-a" means. It has to do with
abstraction levels.

The answer to the "is a circle an ellipse, or is an ellipse a circle"
problem is simple: Neither. Not from an object-oriented design point of
view. Both a circle and an ellipse are at the *same* abstraction level
and hence they do not share a direct inheritance relationship. The
relationship between a circle and an ellipse is the same as the
relationship between a circle and a square: They may both be drawing
primitives, but otherwise they are not directly related.

> In a message passing programming language, there is no necessity for
> GUI elements to share a common base type, they only need to implement
> a common interface (spacial placement, observable, GUI event
> observer ...)

I see no relevant difference from an OO design point of view.
Different technologies, same design principles. "Common interface" is,
basically, the exact same thing as "common base type", from a design
point of view.

Michael Doubez

unread,
Mar 10, 2010, 6:50:11 AM3/10/10
to
On 10 mar, 00:58, Juha Nieminen <nos...@thanks.invalid> wrote:
> Michael Doubez wrote:
> > I wouldn't go as far as say it is flawed, it just that IMO is-a has
> > just the dose of familiarity that makes it dangerous: it lets you
> > believe you can think in terms of concept and map them with the
> > programming language.
>
>   You just have to understand what "is-a" means.

I could expect to have a bit of help from the name.

> It has to do with abstraction levels.

At one point abstraction creates its own artifact and becomes an
ontology of your problem/solution space. Saying that something 'is-a'
<foo> only reflects some organization of the thinking process.

It is not a bad thing, it is just that one name (is-a) is used to
reflect all relations that can appears (specialisation,
abstraction ...)

>   The answer to the "is a circle an ellipse, or is an ellipse a circle"
> problem is simple: Neither. Not from an object-oriented design point of
> view. Both a circle and an ellipse are at the *same* abstraction level
> and hence they do not share a direct inheritance relationship. The
> relationship between a circle and an ellipse is the same as the
> relationship between a circle and a square: They may both be drawing
> primitives, but otherwise they are not directly related.

It also has to do with a specific problem space. For another problem,
it may be be valid for 'circle' to inherit (public) from 'ellipse'. We
always come back to the interface and its semantic behavior.

> > In a message passing programming language, there is no necessity for
> > GUI elements to share a common base type, they only need to implement
> > a common interface (spacial placement, observable, GUI event
> > observer ...)
>
>   I see no relevant difference from an OO design point of view.
> Different technologies, same design principles. "Common interface" is,
> basically, the exact same thing as "common base type", from a design
> point of view.

Except that in order to be provably correct, subtyping requires LSP
while duck-typing doesn't (not as strongly at least). Well, I don't
want to (re)start a static/dynamic typing holy war.

--
Michael

0 new messages