The power of reuse: putting Multiple Inheritance to work

The real methodological imperative

Multiple inheritance is evil. It violates some principle of good design (not sure which one, though, but someone told me so). It will spoil your teeth and ruin your love life. Right?

Wrong. Granted, such conventional wisdom is probably what you have heard if your introduction to object-oriented programming was not through Eiffel. But the problem is not with multiple inheritance. It is with languages that made a mess of it and gave it a bad name. If you ever tried to use “virtual base classes” in C++ or were forced to use an “interface” in Java or C# when you needed a class, you know what we are talking about.

Done right, multiple inheritance is a powerful abstraction mechanism, and an indispensable tool in the programmer’s constant fight to provide simple solutions to complex problems.

Two are often better than one

The role of multiple inheritance is as essential as it is easy to define: combining abstractions. We do this all the time in our daily discussions: a plane has an altitude, a speed, it can take off, it can land; an asset has a value, a depreciation rate, it can be sold; a company plane takes its properties and operations from both of these notions. It has a speed, and it has a value; it can be sold, and it can land. In software modeling, the class COMPANY_PLANE will inherit from both the classes PLANE and ASSET.

Examples abound in the daily practice of software development. A simple one involves the library classes NUMERIC, describing numbers (with the four usual arithmetic operations, zero, one etc.) and COMPARABLE (describing objects that can be compared with an order relation). Not everything that’s numeric is comparable (complex numbers do not have an order relation) and not everything that’s comparable is numeric (strings cannot be multiplied or divided). But sometimes we need to combine the abstractions. The library classes INTEGER and REAL (floating-point numbers) inherit from both NUMERIC and COMPARABLE. A typical example of a situation where there is no reasonable object-oriented design without multiple inheritance.

“Interfaces”

Java and C# propose an ad-hoc workaround to the absence of multiple inheritance: using so-called “interfaces”. A class can inherit from just one class, but any number of interfaces. This concept, however, does not solve the problem: an interface can only have fully abstract (deferred) operations (methods, routines, functions). In most uses of multiple inheritance, such as the above, both sides need implementation. For example in COMPARABLE, even if “less than” is abstract, other operations such as “greater than” and “less than or equal” must be implemented (in terms of “less than”).

Anything less than full multiple inheritance bridles the designer’s creativity and unnatural architectural choices, leading to unmaintainable code. After all, who wants to have to choose between their mother and their father?

A simple, safe renaming policy

One of the reasons multiple inheritance has been maligned (or messed up) is the problem of name conflicts: what if C inherits from A and B, both of which have an operation called f? But the solution is simple. In Eiffel, such a conflict would make C invalid, but you remove it simply by renaming one (or both) of the inherited versions in C.

You write for example rename f as A_f in the clause in C stating that C inherits from A. Then f will be known, in the code of C, under the new name. It’s still the same operation, simply with a different name. Like when you go to Louisiana: there are no “counties”, they are called “parishes”, but it’s still the same concept. Only the name has changed. Simple and safe, in the Eiffel tradition.

And fast too

The other concern about multiple inheritance is the performance impact. Bad implementations cause expensive run-time method lookups. No such worry in Eiffel: we invented the first efficient implementation of dynamic binding, which works perfectly in the multiple inheritance case, with constant-time resolution and very fast execution.

We know that we do not just want your programs to be reliable, easy to change, reusable, and to develop them quickly: you want the best run-time performance as well. Multiple inheritance does not affect that picture.

Put multiple inheritance to work for you

There is no need to settle for crippling language mechanisms. Discover why Eiffel programmers cannot live without multiple inheritance, and use it to produce striking designs: simple, clear, easy to explain, and easy to maintain. Try for yourself the power of multiple inheritance and unleash the power of Eiffel.

Use multiple inheritance by downloading EiffelStudio and following the instructions on multiple inheritance within the Eiffel Documentation.