This article is from the FAQ, by with numerous contributions by
L16) Why doesn't BETA have multiple inheritance?
[Ole Lehrmann Madsen (firstname.lastname@example.org) writes:]
I shall try to explain why there is no (traditional) multiple inheritance in
BETA. Please note that I am not trying to argue against MI. The following is
only an attempt to explain why it is not in BETA.
When BETA was designed we did not think that the concept of multiple
inheritance was ready for being incorporated in the language. One of the
main design goals for BETA was that it should be good for modelling. Most
usages of MI seemed to be for pure code reuse, i.e. a new class may be
defined by inheriting from a number of classes and then redefining the parts
that should differ. Often this is done without there being any conceptual
relation between the new class and the ones it inherits from. We did not
like that way of using inheritance.
MI in BETA should be there to model classification hierarchies which are
non-tree structured. In my experience, such hierarchies are rare in
practice. What is more common is that you may want several independent
tree-structured classification hierarchies for the same objects. A set of
person objects might be classified according to their profession,
nationality, and religion. This gives three class-hierarchies. People often
handle such situation using MI, but this will merge the hierarchies in a way
that makes it difficult to identify the three original ones.
We would like to support such independent classification hierarchies in
BETA, but no concrete proposal exists.
The various proposals for solving name conflicts and overlapping
superclasses also seemed rather complex. We did not want the semantics of
basic constructs to be complicated to understand.
For BETA there are a number of additional problems:
* Virtual patterns from a common superclass may have conflicting bindings
in the superclasses:
A: (# V:< A1; ... do ... inner ... #);
B: A(# V::< A2; ... do ... inner ... #);
C: A(# V::< A3; ... do ... inner ... #);
D: B & C (# V:: A4; ... do ... #);
(The syntax B & C has tentatively been used for MI in BETA.)
Here A2 and A3 must both be subclasses of A1, and A4 must be a subclass
of both A2 and A3. (In her Ph.D. Thesis, Kristine Thomsen defined a
language along these lines, which handled virtual bindings a la those
in BETA. It should be available from the Computer Science Department,
* The semantics for combining inners of multiple superclasses must also
be defined. In the example above, should B's do-part be executed before
C's or vice versa? Since we are not in favour of making the order of
superclasses significant, we were considering letting the execution
order of B and C be non-deterministic, in the sense that the
implementation may execute B or C in any order. (Thomsen's thesis also
deals with combing inners and proposes a number of other alternatives.
You may also want to take a look at: K. S. Thomsen: "Inheritance on
Processes, Exemplified on Distributed Termination Detection",
International Journal of Parallel Programming, pages 24-37, November
Finally, we have not felt an strong need to support MI in the traditional
sense, since BETA has other means for handling some of the most common MI
In BETA you may inherit from part-objects and at the same time further-bind
A: (# f:< ... #);
B: (# g:< ... #);
C: (# ...
X: @A(# f::< (# ... #); ... #);
Y: @B(# g::< (# ... #); ... #);
X and Y are singular part-objects; due to BETA's block structure the virtual
bindings of f and g may refer to variables in the enclosing C-object.
Given the declaration W: ^C, the functions f and g may be invoked as W.X.f
and W.Y.g. The difference from MI is that you have to qualify using X and Y.
Some people think of this as an inconvenience; others think of it as an
advantage since it forces them to be explicit about name conflicts between A
and B. If you prefer writing W.f and W.g, you may define f and g functions
in C and let them forward the calls to X.f and Y.g.
Given the declaration V: ^A, then W.X->V is possible, and an invocation
of V.f calls the further-binding of f in X, thereby possibly
accessing/changing the state of C.
To sum up, this form of multiple inheritance via part objects is very
similar to non-overlapping inheritance in C++.
As a final example, consider the following well-known MI case:
In BETA this may be handled using block-structure
Border: (# ... #);
Title: (# ... #);
W1: @Window(# B: @Border; T: @Title #);
W2: @Window(# T1,T2: @Title #);
Here W1 has a border and a title, whereas W2 has no border and two titles.
(For a further discussion, see K. Osterby: "Parts, Wholes, and Subclasses",
Proceedings of the 1990 European Simulation Multiconference, pages 259-263,
To sum up, we did not think that traditional MI has been worth the
complications it will add to the language, since many of the MI cases can be
handled by other means. We are, however, still discussing MI, and it may end
up being supported more directly.