News:

This week IPhone 15 Pro winner is karn
You can be too a winner! Become the top poster of the week and win valuable prizes.  More details are You are not allowed to view links. Register or Login 

Main Menu

c++ tips - Inheritance, libraries, and mixins

Started by ben2ong2, October 07, 2006, 09:39:21 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

ben2ong2

This picks up on a dialog between You are not allowed to view links. Register or Login (SRH) and
John Skaller (JMS) on May 15, 1993 ...

SRH:

I would like to recap some of the discussions here and in the periodicals about
inheritance.

(1) The biggest problem seems to be the name inheritance.  Programmers get
confused by the term inheritance when they try to use the term like a biologist
might. 

You may say you inherited your blue eyes from you mother.  What does
this mean?  This means you and all other humans have an attribute called eye
color and you received the value of blue from your mother.  This works for
biologists, but not for programmers.  Inheritance in programming is only
effective if we inherit attributes instead of values for attributes.

JMS:

   Inheritance only works for abstract functionality.
Basically: only useful for abstract classes, and this sort of
inheritance is *composition*.

   The sort of derivation called *subclassing* is for *implementing*
abstractions: there is no inheritance here at all, on the contrary,
instead of inheriting some attribute you are *defining* it.

SRH:

(2) Another problem is using the inheritance feature to model *dynamic
classification*.  We have dynamic classification if we say a sea plane inherits
from boat and plane.  The inheritance feature in C++ is inappropriate here
because a vehical is either a boat or a plane, not both at the same time. A sea
plane is better modeled as a class that contains a pointer to a state diagram
that implements a finite state automoton.

JMS: [...]

(3) There is an important distinction between natural and synthetic
inheritance.  Synthetic inheritance is just using the feature in the language
because it makes the programmer's job easier which is in contrast to natural
inheritance which is using the feature in the language to express a
relationship that has been observed (i.e., abstracted) from the application
domain. Using MI for natural inheritance seems to be very rare in the
literature.

JMS: [...]

SRH:

Do you think mix-ins are mainly used for natural or synthetic inheritance? The
examples of mix-ins that John Skaller and I have come up with make wonder if
mix-ins are primarly used for synthetic inheritance.

JMS:

   Its confused because the Smalltalk idea of inheritance
and subclassing is unrelated to the C++ idea. In C++, subclassing
is for *implementing* an abstraction. It embodies the 'isA' relation.
In C++ one 'type' cannot *be* another type. You can only have
an *implementation* of a type, or, another implementation of the *same*
type.

   The implementations should be hidden .. so the user
only sees one type: the subclasses are invisible.

   Is this natural or synthetic? I dont know, but I think
you are probably correct in saying its synthetic. What that
means is that inheritance is *never* used for natural
purposes in C++ because every such use is an error.
(Or rather, when it *is* used, it is used with abstractions
where we really mean to use composition not subclassing)

   But most of the OO examples in the literature are 'natural'
ones that Smalltalk supports. C++ doesnt support that paradigm
at all. (well, it does if you use downcasting and RTTI :-)

SRH:

If you don't count the mix-in examples as natural multiple inheritance, then
the only example of natural multiple inheritance I have seen, after repeatedly
soliciting this news group for examples, is the bank account example. (First I
solicited for text book examples of MI, and then any example of MI).

JMS:
   Gak. Thats not a good example really.

SRH:

(4) Composition is sometimes superior to inheritance because you can give the
sub-object a name thus making your code much easier to deal with. 

JMS:

   Its not 'sometimes superior' as if you ought to have a choice.
Either you should use composition or subclassing. You may have to
decide what you really mean: that design choice determines the correct
technique usually.

SRH:

If you want
your class to receive additional member functions, there is merit to making
your member object public.  This is much  easier than manually alleviating
a lot of conflicting member function names resulting from multiple inheritance.

JMS:

   I've never had a problem with conflicting member names using MI.

SRH:

(5) Virtual inheritance is really messy as pointed out in the recent article in
the C++ report on FJI (Fork Join Inheritance).  The fact that initializer lists
are ingored for all but the most derived class is very frightening because it
is a terribly violation of the user-provider model of programming where the
user is permitted to be ignorant of the implementation of the classes he uses.

JMS:

   Not really. Generally, virtual bases are abstract classes,
and dont need *any* initialisation (other than vtable set up).

   How do you initialise an abstraction?

SRH:

Incidently, FJI is very interesting.  Has anybody come up with a use for it? It
is especially interesting when the same sub-object can have both virtual and
non-virtual paths to the same descendant.  This really boggles my mind -- why
would anybody even want to think about doing that?  Looks to me like FJI could
cause permanent drain bamage (typos intended) in a maintenance programmer.

JMS:

   No, it can be confusing and hard to figure out .. it sure is
hard to debug, but it is essential to come to grips with it because
it is *the* technique of polymorphism.

   Anything less than mixins is relatively powerless, anything
more is not safe.

SRH:

(6) Even if you are astute enough to effectively grasp points 1-4, we still
have the problem that most compiler writers don't understand MI. At this time
it is not reasonable to assume that your compiler implements MI correctly.  See
Tom Cargill's book for a short test program that reveals a bug in most
compilers.

JMS:

   Right. According to my latest survey a few months ago,
about 1/3 compilers got it right .. but the number is rapidly increasing.

   Dont forget there is no standard for the compiler writers to
meet: its hard to produce a complex program without a proper specification.

SRH:

(7) Mix-ins are difficult to use in C++ as Bjarne explaines in the ARM (page
202).  This is because unlike LISP, C++ does not have deamons (which is a
feature that allows method combination). Neither does C++ have a feature like
Smalltalk's super-send mechanism to preform preprocessing.  I'm working on a
tutorial on how to simulate deamons in C++ to make mix-ins work -- but I have
not seen anyone else write about it.  Does anyone know what other OO languages
do about this problem of method mixing?  What does simula and eiffel do about
it for example?

JMS:

   This is largely unrelated to what I call mixins. Dont confuse
Multiple inheritance with mixins: MI is one of the language features
required to implement mixins.

   For me, mixin technology is about incremental development.
It is enabled by use of polymorphism: late binding. This has very
little to do with delegating to a base class function.

   It has nothing to do with method mixing. It has to do
with sideways definition of pure virtual functions.

SRH:

Well does that sum it up?  Have I missed anything?

JMS:

   Mm. You did cover quite a lot. I more or less claim
mixins are the proper way to use inheritance for subclassing,
that is, how to get the maximum benefit out of polymorphism
and also achieve reusability.  I dont know *any* other technique
that is statically secure that does this.

   Delegation is more powerful than mixins, and function pointers
are more powerful than delegation, but neither is completely safe.

      AbstractClass1      AbstractClass2
      /   \      /   \
   Implement1   AbstractClass12      Implement2
      \      |      /
      ConcreteMixinClassNumber12

You can switch Implement1 for Implement1A and the same for Implement2
*independently*. Thats the key point: you can construct the
abstraction "AbstractClass12" and the mixin class as you need them,
and choose the particular implementation subclasses as you need.

The idea of a mixin library is to have mainly the AbstractClassX
classes and the ImplementX classes. The rest is done by the programmer
as required.

So the library consists of components like:

      AbstractClass1         // abstract base
      /   |   \
   Impl1      Impl2   Impl3      // implementation subclasses

Can you see how this is nice? Its called mixins because you can
mix-up the abstractions (design) you want, then make them from selected
parts (code) that you think are suitable/optimal. The Implementation
classes are 'plug compatible'. Mixing up the abstractions is like
designing the circuit boards.

So you have both design reuse and code reuse of library components.

The major problem with this technique is thats its *really hard*
to design the abstractions so they work together well. You have to
do this to prevent your library exploding with abstractions.

And to prevent pwogwammer bwane dambage (sic :-).

You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login