[comp.object] How to use Inheritance instead of nesting

staff@cadlab.sublink.ORG (Alex Martelli) (08/08/90)

>In general, multiple inheritance is almost never needed.  I have never
>seen a published example of a C++ program using multiple inheritance
>that couldn't be coded just as easily using components instead.  (This

This is a major thesis of T. Cargill, and he's been propounding it at
Usenix and UKUUG; indeed, he has rewritten all published examples of
multiple inheritance in C++, with single inheritance or none at all,
and they're better (see the proceedings of the above conferences).

>is not true for some other systems, such as flavors.)  Sometimes multiple
>inheritance is the best way to think of a problem, but it is grossly misused

I wonder!  Yourdon and Coad, in "Object-Oriented Analysis", claim that
M.I. is no doubt great as a CODING technique, e.g. for C++ 2.0, but for
ANALYSIS ("best way to think of a problem"), they shun it as leading to
unwarranted complication in "modeling the problem space".  If the
analysis theoreticians want MI only in coding, and the coding freaks
want to leave MI for analysis, what does this suggest...?

>in the C++ world.  I would be happy for people to point me to examples of
>multiple inheritance in which it is obviously better than any of the
>design alternatives.

The best cathegory of examples I have seen in books/articles/talks by
Bertrand Meyers, and it has to do with parametric classes with some
constraints on operations which need to be available on the formal
types which are the parameters.  Instead of ad-hoc, weakish expression
of the constraints like in Ada, one can say, for example:
"generic class AVL_TREE of T:COMPARABLE" to express the fact that the
T parameter of AVL_TREE must inherit from COMPARABLE, which presumably
one has already coded as an abstract class specifying the comparison
operator (including some of its semantic constraints, in assertions);
now in the code for AVL_TREE I can invoke the comparison operator on
objects of formal type T.  With MI, this does not really limit what
can be put on an AVL_TREE!  Suppose I have a class WORKSTATION, which
of course has NOT inherited from COMPARABLE, but does have a
SERIAL_NUMBER attribute; I can make a COMPARABLE_WORKSTATION with MI
from WORKSTATION and COMPARABLE, by implementing the comparison as
being done on the serial numbers, and have an AVL_TREE of them for
inventory, look-up, etc.

Of course I *could* do the same by just inheriting from COMPARABLE
and HAVING a field of type WORKSTATION, rather than BEING a workstation;
in general, the IS-A and HAVE-A relations are not as disjoint as one
would think in the first place!  However, I would then have some 
trouble applying other WORKSTATION ops & data structures to them.

I have obviously not yet thought enough about these topics, but it
seems to me they're deeply connected with the dual nature of class
inheritance - inheritance of SPECIFICATIONS for an interface, and of
IMPLEMENTATION... I would welcome a discussion on this, and of MI
in general.

Also think of the practical concerns - maybe there are cases where
MI would not be needed IF one could redesign each and every class
hierarchy from scratch, but MI makes it easier to reuse specs and
code, maybe from vendor-bought hierarchies, WITHOUT redesign...?

-- 
Alex Martelli - CAD.LAB s.p.a., v. Stalingrado 45, Bologna, Italia
Email: (work:) staff@cadlab.sublink.org, (home:) alex@am.sublink.org
Phone: (work:) ++39 (51) 371099, (home:) ++39 (51) 250434; 
Fax: ++39 (51) 366964 (work only; any time of day or night).

cox@stpstn.UUCP (Brad Cox) (08/12/90)

In article <243@cadlab.sublink.ORG> staff@cadlab.sublink.ORG (Alex Martelli) writes:
>
>>In general, multiple inheritance is almost never needed.  I have never
>>seen a published example of a program using multiple inheritance
>>that couldn't be coded just as easily using components instead.  
>
>I have obviously not yet thought enough about these topics, but it
>seems to me they're deeply connected with the dual nature of class
>inheritance - inheritance of SPECIFICATIONS for an interface, and of
>IMPLEMENTATION... I would welcome a discussion on this, and of MI
>in general.

You and Cargil are on the money with this issue. There is so much
confusion about what OO really means because it seems to offer something
for the two traditional camps in software; those who believe software is
abstract, like mathematics (who like inheritance & static binding), 
and those who believe software is concrete, like engineering (who like
encapsulation and dynamic binding).

By supporting inheritance and encapsulation together, OOPLs are like a handsaw
(implementation tool) with a ruler (specification tool) taped onto the side.
The result is not totally ridiculous, for having both capabilities in
the same tool can be convenient for occasional (hobby) work. But the serious
craftsman realizes that specification tools and implementation tools are
tools for fundamentally different, but closely related, jobs, and builds
up astonishingly diverse collections of specification tools over here
and implementation tools yonder; together, but ever apart.

My IEEE Software paper (Nov 1990) goes into the distinction between 
specification and implementation in some detail, and argues that we must
stop relying so heavily on inheritance in our implementation tools, and
start devoting as much attention to creating specification tools as we
have on OOPLs. This doesn't mean ripping out inheritance from existing
OOPLs, but just knowing that the meaning of inheritance as supported there
is as an implementation tool, not a specification tool.

Where inheritance really belongs, and where it offers its greatest
potential, is in the (as-yet-nonexistent) specification tools; i.e.
specification language "compilers" that compile an input notation, the
specification, into but *tests*; executable code, or "gauges", that determine
(by testing) whether a given implementation is within tolerance to its 
specification.

In case this isn't obvious, the meaning I'm using for "specification"
includes not only *static* specifications (i.e. what method names/types
are listed in some interface file; i.e. class Stack has methods push and pop),
but *dynamic* specifications (i.e.  if I push 1,2,3 on an instance of class
Stack, pop should return 3,2,1).

Inheritance should work extremely well in this domain, far better than
it does in implementation languages. 

The problems with even simple single inheritance, which become vastly 
magnified with multiple inheritance, are why we never supported multiple
inheritance in Objective-C. Instead, we're focusing on providing multiple
inheritance where it might do more good than harm, in a parallel 
specification language, still under development.

Do you think we should call the new one Subjective-C? ;-)
-- 

Brad Cox; cox@stepstone.com; CI$ 71230,647; 203 426 1875
The Stepstone Corporation; 75 Glen Road; Sandy Hook CT 06482

gregk@cbnewsm.att.com (gregory.p.kochanski) (08/12/90)

In article <5456@stpstn.UUCP> cox@stpstn.UUCP (Brad Cox) writes:
>In article <243@cadlab.sublink.ORG> staff@cadlab.sublink.ORG (Alex Martelli) writes:
>>I have obviously not yet thought enough about these topics, but it
>>seems to me they're deeply connected with the dual nature of class
>>inheritance - inheritance of SPECIFICATIONS for an interface, and of
>>IMPLEMENTATION... I would welcome a discussion on this, and of MI
>>in general.
>
>My IEEE Software paper (Nov 1990) goes into the distinction between 
>specification and implementation in some detail...
>
>Where inheritance really belongs, and where it offers its greatest
>potential, is in the (as-yet-nonexistent) specification tools...
>
>In case this isn't obvious, the meaning I'm using for "specification"
>includes not only *static* specifications (i.e. what method names/types
>are listed in some interface file; i.e. class Stack has methods push and pop),
>but *dynamic* specifications (i.e.  if I push 1,2,3 on an instance of class
>Stack, pop should return 3,2,1).
>
>Do you think we should call the new one Subjective-C? ;-)

Won't the process of writing the specifications be as complex as writing
the program, if you want to specify things in such detail that all
operations of a class can be tested?

Without attempting to make fun of these ideas -- I think that having
even a partial automated testing sceme would be a big improvement--
I'd like to point out that these ideas have already appeared, although
not yet implemented:
                    <<< TLE::PUBD$:[VAXNOTES]VAXC.NOTE;1 >>>
                                -< VAX C Notes >-
================================================================================
Note 133.0                    Subjective C Revealed                   No replies
REX::MINOW                                           94 lines   3-APR-1985 09:03
--------------------------------------------------------------------------------

Forwarded from the ARPA AI-LIST for your enjoyment:


Date: 1 Apr 1985 16:05:34 EST (Monday)
From: PSN Development <psn@bbn-noc3.arpa>
Subject: subjective C

          [Forwarded by Susan Bernstein <slb@BBNCCP.ARPA>.]


            Subjective C, a new programming language.

Recently researchers in the computer language field have shown much
interest in subject oriented languages.  Subjective programming
languages draw upon concepts developed in the fields of subjective
probability and philosophical subjectivism to enrich the field of
programming semantics.  `Subjective C' is such a language based on the
programming language C.

Subjective C grew out of the AI concept of DWIM, or "do what I mean".
The subjective C compiler infers the mood of the author of the input
program based on clues contained in the comments in the program.  If no
comments (or verbose identifiers) are present, the programmer is judged
to have insufficiently thought out his problem, i.e.  to have
insufficiently specified the computation to be performed.  In this case
a subjective diagnostic is issued, depending on the compiler's own mood.
Assuming comments or other mood indicators are present, an amalgam of
inference techniques drawn from various reputed-to-be-successful expert
systems are used to infer the author's mood.

A trivial example of a mood revealing comment with accompanying program
text is the following:

        a = a - 1;      /* add one to a */

A too simple analysis of the dichotomy between apparent meaning of the
statement and accompanying comment is that one of them is in error.  A
more insightful analysis is that this program should not be allowed to
work, even if no syntax errors occur in it.  Accordingly, subjective
compiler should hang the system, thus inducing the programmer to quit
for the night.

More interesting cases occur when there is no conflict between program
text and commentary.  It is these cases where Subjective C is shown to
be a significantly richer language than normalcy.

Some examples of mood-implying comments found in actual programs are the
following:

        ; Here we do something perverse to the packet.  Beats me.

In this case, the comment reveals that the programmer does not care what
the code does, except that he wants it to be something that subsequent
programmers will be shocked by.  The compiler uses a variation of its
mood-inference techniques to generate code that is suitably perverse by
systematically generating actions and evaluating them against the
criteria it has synthesized.

        blt                     ; hold the mayo

The Subjective C compiler evaluates the indicatory content of this
comment to discern that the programmer is undoubtedly hungry.  Code will
be generated that will crash inexplicably, thus inducing the programmer
to go to the candy machine and pig out, which is what he wanted in the
first place.

Subjective C is neither a superset nor a subset of "normal" (if one can
apply the term) C, known in subjective parlance as normalcy.  However,
there is an extensive intersection, if meanings of programs are ignored.
The central thesis of research in the field of subjective languages is
that the meanings of programs are far more subtle than first appears to
the reader (or author).

Some examples of mood revealing comments in well known C programs
include the following:

        /* I've been powercoding much too much lately.  */ and,

        /* WARNING: modify the following at your own risk. */


Students of program complexity will be interested to note that the
algorithms used for mood inference are of greater complexity than NP
complete, which is of one of the first known practical applications of
this class of computations.  The exact characterization of this class of
problems is not yet fully explored, but some initial theoretical results
will be published by certain graduate students, real soon now, and no
later than next August when their fellowships run out.

The subjective C compiler, called "see", will be available (relatively)
shortly on all bbn unix systems.  Comments can be directed directly
to the compiler itself, in the usual fashion.

hansen@pegasus.ATT.COM (Tony L. Hansen) (08/17/90)

< From: staff@cadlab.sublink.ORG (Alex Martelli)

<< In general, multiple inheritance is almost never needed.  I have never
<< seen a published example of a C++ program using multiple inheritance that
<< couldn't be coded just as easily using components instead.

< This is a major thesis of T. Cargill, and he's been propounding it at
< Usenix and UKUUG; indeed, he has rewritten all published examples of
< multiple inheritance in C++, with single inheritance or none at all, and
< they're better (see the proceedings of the above conferences).

< Also think of the practical concerns - maybe there are cases where MI
< would not be needed IF one could redesign each and every class hierarchy
< from scratch, but MI makes it easier to reuse specs and code, maybe from
< vendor-bought hierarchies, WITHOUT redesign...?

Let me try to summarize Tom Cargill's position on multiple inheritance (MI):

    o	He has been able to rewrite all published examples of MI using
	either single inheritance (SI), composition (using member variables),
	or both.

    o	He feels that the rewritten versions are cleaner and easier to
	maintain.

    o	One exception which he concedes is in the use of multiple vendor
	libraries, which might possibly be combined through MI.

    o	In either case, he feels that virtual bases are not necessary
	because those are ONLY needed when designing in MI and he feels that
	the alternative designs using SI and composition are better.

    o	Tom is also on the lookout for a use of MI which absolutely cries
	out for MI and can't be cleanly done any other way.

I feel that the concepts of "cleaner" and "easier to maintain" are very
subjective. I think that thinking in terms of MI may suggest a solution to a
problem more quickly, or may suggest alternate ways of thinking about the
problem, even if you don't wind up using MI in the end. In other words, it's
a tool in your toolbox that shouldn't be categorically denigrated.

I've yet to be convinced one way or the other by Tom's arguments.

					Tony Hansen
				att!pegasus!hansen, attmail!tony
				    hansen@pegasus.att.com