[comp.lang.ada] Does Ada really need MULTIPLE inheritance?

NCOHEN@IBM.COM ("Norman H. Cohen") (10/16/89)

Two recent workshops focused on adding support for object-oriented
programming to Ada.  One, sponsored by MITRE Corporation, was held
September 11-13 at Woburn, Massachusetts.  The Workshop on Language
Issues for Reuse: Ada for the 90's, sponsored by University of Maine
was held at Deer Isle, Maine, September 25-29.  Specific proposals for
supporting object-oriented programming in Ada were discussed at each
workshop.

I'll leave discussion of the details to the final workshop reports, which
are now in preparation, but I do want to mention two areas of consensus
reached at both workshops:

   (1) Ada should support inheritance.
   (2) There is no convincing need for MULTIPLE inheritance.

Since nobody at either workshop was a strenuous advocate of multiple
inheritance, I would like to see the argument for multiple inheritance
presented here.  Among the thoughts that contributed to the consensus
AGAINST multiple inheritance were:

   (1) In many cases, the effect of multiple inheritance could be
       achieved also by instantiating a generic unit defining a subclass
       of a class given by a generic parameter.  This allows different
       classes to be extended in a uniform way.

   (2) Multiple inheritance may seem essential in some object-oriented
       languages because inheritance is the only importation mechanism.
       Ada can get by with a WITH clause in many contexts where other
       languages use multiple inheritance.  In Eiffel, for example, one
       inherits from class MATH, which has operations but no state data,
       to achieve the effect of WITHing a math package in Ada.

   (3) In some language proposals, multiple inheritance is a natural
       generalization of single inheritance.  In other proposals,
       however, multiple inheritance is difficult to accommodate.
       For example, the view that subclasses should be treated as Ada
       subtypes has much going for it (for details, see my proposal
       "Ada Subtypes as Subclasses," Research Report RC14912, which can
       be obtained by writing to IBM Thomas J. Watson Research Center,
       Distribution Services F-11 Stormytown, P.O. Box 218, Yorktown
       Heights, NY 10598), but it is incompatible with multiple
       inheritance in a strongly typed language like Ada.

   (4) Many (including Bertrand Meyer) hold that the inheritance
       hierarchy should reflect an "is-a" relationship.  That is, each
       instance of a subclass should be an instance of its immediate
       superclass(es) as well.  There are a few well-known examples
       where the "is-a" relationship holds with multiple parents (a text
       window is both a text file and a window, e.g.) but such examples
       are rare, too rare to justify further complication of the
       language.

   (5) Multiple inheritance makes it difficult to determine the source
       of a subclass's features, or to determine the impact of changing
       the interface of a superclass.  It tends to lead to undisciplined
       software composition that may be fine for exploratory programming
       but is unacceptable for the huge projects in which Ada is used,
       projects that require strict configuration management.

Norman Cohen

eichmann@h.cs.wvu.wvnet.edu (David A Eichmann,316K) (10/18/89)

From article <8910161521.AA27039@ajpo.sei.cmu.edu>, by NCOHEN@IBM.COM ("Norman H. Cohen"):
...
> Since nobody at either workshop was a strenuous advocate of multiple
> inheritance, I would like to see the argument for multiple inheritance

OK, let's say I'm creating refinements of a general concept of vehicle,
which contains two attributes, means of propulsion(motor, air, etc.) and
operating medium(land, air, water).  I can make an initial refinement
of air vehicles (adding appropriate attributes), land vehicles, and water
vehicles - refining by medium; or I can refine to motor vehicles, air
(powered) vehicles, etc - refining by propulsion.  With single inheritance,
I must choose one over the other.  With multiple inheritance, there is
no need.  A motorized air vehicle is an instance of both air vehicle AND
an instance of motorized vehicle.  My initial design choice is not coloring
subsequent interpretations and perspectives on the objects in question.


-----
David Eichmann
Dept. of Statistics and Computer Science
West Virginia University                  Phone: (304) 293-3607
Morgantown, WV  26506                     Email: eichmann@a.cs.wvu.wvnet.edu

chase@Ozona.orc.olivetti.com (David Chase) (10/18/89)

I'm not well-versed in Ada, but people I've talked to ensure me that
Ada has something similar to the "opaque types" of Modula-2 and
Modula-3.  Combining opaque types and multiple inheritance can lead to
some nasty problems.  I don't have a solution; just a problem.

I'm assuming that by "multiple inheritance", the people discussing it
means the ability to (1) extend an existing type or (2) refine an
abstract (virtual, in the C++ lingo) type.  In the first case one
might specialize "vehicle" into "car" and "truck"; in the second case,
one might provide a method for "compare" for an abstract "Comparable",
and take advantage of all the code already written to deal with
Comparable objects.

It's the second case, and overriding of existing message-method
bindings in general, that causes the problem.

Suppose I have a type T1, and it has a binding message-method binding
M1-m1a (M1 is the message, m1a is the method for it).  Supposing I
have a type T2 which inherits from T1, and uses the M1-m1a binding.

  T1 = OBJECT METHODS M1() := m1a END;

 T2 = T1 OBJECT METHODS ... END;

Now suppose I export T2 opaquely, along with a procedure P2 which does
something useful with a T2.

 OPAQUE OBJECT T2; (* I'm making up syntax as I go along *)
 PROCEDURE P2(x:T2) ...;

Now suppose I have a type T3 which inherits from T2, and also inherits
from T1, but uses the message-method binding M1-m1b.  I claim that (1)
this should be legal, because the programmer has no way of knowing
that it should be illegal (information hiding, right?) (2) An object O
of type T3 should have the binding M1-m1b where it is visible that O
is a T3 (because that's what the programmer said) (3) An object O of
type T3 should have the binding M1-m1a whenever it is in a context
where it is known to be a T2, but not known to be a T3 (because the
programmer should not be able to invalidate the correctness of a
module if the internals of the module are hidden).

That is (elaborating (3)) if P2 is called, then within P2 the binding
should be M1-m1a, and if O.M1 is sent in that context, then within the
code for m1a the binding should still be M1-m1a.  That is, a second
time, changes to the method bindings for T1 by a subtype T3 *must not*
change the behavior of T3 when considered as a T2; any proofs about
the behavior of a T2 would thus go out the window (and the programmer
would be clueless, because the dependence of T2 on T1's message-method
bindings is hidden).

 T3 = T1, T2 OBJECT METHODS M1 := m2b END;

at some point in the program,

 VAR x : T3;
 ...
 P2(x); (* x MUST act as a T2 in P2, including the binding of
           M1 to m1a. *)
 ...
 x.M1() (* This MUST call method m1b, not m1a. *)

I am *not* arguing that this should be the case if T2 is not opaque;
in that case everything is in the clear, and either an error message
or a change in T2's behavior is allowed.  This nasty situation could
be avoided by creative prohibition (objects cannot be opaquely
exported -- yuck; opaque types cannot be inherited -- yuck; no
multiple inheritance -- many people say yuck, but that's what we live
with in Modula-3), but I'd be even happier if I could figure it out.

David

billwolf%hazel.cs.clemson.edu@hubcap.clemson.edu (William Thomas Wolfe, 2847 ) (10/19/89)

From NCOHEN@IBM.COM (Norman H. Cohen):
> Two recent workshops focused on adding support for object-oriented
> programming to Ada.  [...] I do want to mention two areas of consensus
> reached at both workshops:
>    (1) Ada should support inheritance.
>    (2) There is no convincing need for MULTIPLE inheritance.
> Since nobody at either workshop was a strenuous advocate of multiple
> inheritance, I would like to see the argument for multiple inheritance
> presented here.  

    David Eichmann has presented one; a few more appear below.

> Among the thoughts that contributed to the consensus
> AGAINST multiple inheritance were:
> 
>    (1) In many cases, the effect of multiple inheritance could be
>        achieved also by instantiating a generic unit defining a subclass
>        of a class given by a generic parameter.  This allows different
>        classes to be extended in a uniform way.
> 
>    (2) Multiple inheritance may seem essential in some object-oriented
>        languages because inheritance is the only importation mechanism.
>        Ada can get by with a WITH clause in many contexts where other
>        languages use multiple inheritance.  In Eiffel, for example, one
>        inherits from class MATH, which has operations but no state data,
>        to achieve the effect of WITHing a math package in Ada.

   I would submit that the generic mechanism and the multiple inheritance
   mechanism are conceptually orthogonal; trying to use generics to simulate
   multiple inheritance is like trying to simulate recursion with a stack,
   etc.; although it may be possible, its desirability in terms of program
   clarity is highly questionable.
 
>    (3) In some language proposals, multiple inheritance is a natural
>        generalization of single inheritance.  In other proposals,
>        however, multiple inheritance is difficult to accommodate.
>        For example, the view that subclasses should be treated as Ada
>        subtypes has much going for it (for details, see my proposal
>        "Ada Subtypes as Subclasses," Research Report RC14912, which can
>        be obtained by writing to IBM Thomas J. Watson Research Center,
>        Distribution Services F-11 Stormytown, P.O. Box 218, Yorktown
>        Heights, NY 10598), but it is incompatible with multiple
>        inheritance in a strongly typed language like Ada.

   Subclassing and subtyping are two somewhat similar, but distinct 
   concepts; both need to be properly supported.  I see no reason why 
   this could not be accomplished.

>    (4) Many (including Bertrand Meyer) hold that the inheritance
>        hierarchy should reflect an "is-a" relationship.  That is, each
>        instance of a subclass should be an instance of its immediate
>        superclass(es) as well.  There are a few well-known examples
>        where the "is-a" relationship holds with multiple parents (a text
>        window is both a text file and a window, e.g.) but such examples
>        are rare, too rare to justify further complication of the
>        language.

   I would argue first that such examples are not necessarily rare;
   it may simply be that the lack of an ability to express the idea
   at all has greatly restricted the amount of time spent considering
   the possibilities, and that many valid applications of the concept 
   will emerge once its expression becomes possible.  

>    (5) Multiple inheritance makes it difficult to determine the source
>        of a subclass's features, or to determine the impact of changing
>        the interface of a superclass.  It tends to lead to undisciplined
>        software composition that may be fine for exploratory programming
>        but is unacceptable for the huge projects in which Ada is used,
>        projects that require strict configuration management.

   Determining the source of a subclass's operations can be done
   with an appropriate tool automatically.  Determining the impact
   of changing the interface of a superclass is similar to the problem
   of determining the impact of a change to a package interface; when
   the syntactic interface to a package changes, there is a "direct" 
   impact in that certain portions of code (the code withing the 
   modified spec) must be recompiled.  However, this does not bound 
   the *semantic* impact; semantic modifications can be made without
   even causing recompilation, and can propagate throughout the system
   essentially unchecked.  Consider what would happen if something as
   heavily relied upon as a mathematics package were to be semantically
   modified; newly linked programs everywhere could begin to fail through
   absolutely no fault of their own, whether because of subprograms that
   failed catastrophically as a direct result of the modification or 
   because of subprograms that began to deliver subtly incorrect results.

   The only answer to this, I think, would be to incorporate something 
   like Anna/TSL into the definition of Ada, and even then the costs of 
   specifying and enforcing semantics so tightly would be considerable.  
   In short, there's no easy answer, and no escape from the problem.  

   Finally, the point about it tending to lead to undisciplined software
   composition is certainly not without supporting evidence, in that 
   the capability has so far been most extensively used in support of 
   exploratory programming.  But it is not my purpose to enable
   exploratory programming to be done; my objective is to enable the
   natural expression of real-world relationships, and also to enable
   the systematic reuse of concepts which have already been expressed.  

   Perhaps ideas will emerge which will lead to a means of restricting
   undisciplined use of multiple inheritance, just as ideas such as
   doing type-checking and making any arithmetic difficult have 
   successfully restricted the undisciplined use of pointers. 


   Bill Wolfe, wtwolfe@hubcap.clemson.edu
 

baker@IDA.ORG (Paul Baker) (10/31/89)

>From article <8910161521.AA27039@ajpo.sei.cmu.edu>, 
>   by NCOHEN@IBM.COM ("Norman H. Cohen"):
> Since nobody at either workshop was a strenuous advocate of multiple
> inheritance, I would like to see the argument for multiple inheritance

I attended one of these workshops and didn't advocate multiple
inheritance.  The response to Norm's remark on this network seems to be
based on the notion that the power of multiple inheritance was
overlooked at these workshops.  If my memory serves, the issue on the
table was the value of this feature in the context of its dangers and
the fact that it is not essential for OOP. Its power was recognized.

The danger is that there is currently no rigorous notion of how we shall
interpret the fusion of methods from alternative lineages.  CLOS offers
a fixed and reasonable interpretation of the order of delegation
but the order is not based on any convincing metaphor.  In the face of
this problem, it will be difficult to teach design for multiple
inheritance and hard for one developer to maintain another's system.

Multiple inheritance is not essential because its effects can be
achieved by defining a new class whose slots include components from
various classes.  The developer must then define all the new methods -
none are inherited automatically.  Naturally, that new definition can
be a delegation to one of the ancestor classes. Thus, composition
achieves the same functional effect as inheritance but requires an
explicit explanation of the intended fusion of methods.

----------
Paul L. Baker
CTA INCORPORATED
E-MAIL: bakerp@ajpo.sei.cmu.edu  PHONE: 301-816-1242