[Prev][Next][Index][Thread]

Re: MI: why?



>>>>> "Scott" == Scott Ribe <sribe@miqs.com> writes:

    Scott> jt wrote:
    >> [..] I have heard a lot of condemnation
    >> of multiple inheritance. [..]

    Scott> Multiple inheritance does present some difficult issues,
    Scott> and the C++ implementation is particularly filled with
    Scott> potential traps. (Thus it fits right in with the rest of
    Scott> the language!) 
    Scott> [lots of great, interesting stuff]

    Scott> (Beta is an exception. It looks nice to me, yet is
    Scott> SI. Where's the disconnect?)

Multiple inheritance in BETA is hard! :-) 

[shameless plug begin]
It is supported in gbeta (similar to the tradition in CLOS and Dylan
in that it is based on linearization), and was described here:

  Erik Ernst. Propagating class and method combination. In Rachid Guer-
  raoui, editor, ECOOP'99 -- Object-Oriented Programming, volume 1628 of
  Lecture Notes in Computer Science, pages 67-91, Lisboa, Portugal, June
  1999. Springer-Verlag.

The gbeta web site is at <URL:http://www.daimi.au.dk/~eernst/gbeta/>.
[shameless plug end]

The reason why it is non-trivial to add MI to BETA is that the
interaction between general block-strucure, virtual attributes, and MI
creates a phenomenon which is called "propagation" in the above
paper.  It might be described as a language mechanism for aspect
oriented programming.  One special case is that the combination of two
classes may combine the implementation of their methods (similar to
the effect of `before' and `after' methods in CLOS).  Another special
case is that the combination of two methods may combine the types of
their arguments and results.

As you can see, this is actually about enhancing the effects of
combinations.  The traditional MI semantics is to take the union of
the sets of attributes (to "add" the classes) and *choose* between
conflicting definitions with the same name based on specificity ("the
subclass method wins", etc).  The idea behind the propagating
combinations is to *combine* conflicting definitions in a recursive
scheme.

The two examples above are only two-level instances.  Here is a
three-level example: Assume we have a class "Graph" which contains two
(virtual) classes "Node" and "Edge".  "WeightedGraph" and
"ColoredGraph" are two subclasses of "Graph".  The "Edge" class of a
"WeightedGraph" would add a "weight" to the "Edge" inherited from
"Graph", and the "Node" and "Edge" classes of a "ColoredGraph" would
add a "color" to the inherited classes of the same name.  Various
methods of "Graph", "Node" and "Edge" would be extended to handle the
special requirements of colors and weights.  Then we could, with the
syntactically concise expression

  CWGraph: ColoredGraph & WeightedGraph,

create a new kind of graph "CWGraph" with contributions ("aspects")
from both "WeightedGraph" and "ColoredGraph".  Since this would
implicitly combine the implementations of, e.g., the methods of
"Node", it would span three levels: The outermost "CWGraph", the
nested "Node" and the method inside "Node".  Of course, any number of
levels may be used, but it would probably be most manageable if only
a few levels were used in practice, just like we don't like
inheritance in 123 levels..  :-)


 regards,

-- 
Erik Ernst                                    eernst@cs.auc.dk
Department of Computer Science, University of Aalborg, Denmark



References: