What is the exact problem with multiple inheritance?
Solution 1:
The most obvious problem is with function overriding.
Let's say have two classes A
and B
, both of which define a method doSomething
. Now you define a third class C
, which inherits from both A
and B
, but you don't override the doSomething
method.
When the compiler seed this code...
C c = new C();
c.doSomething();
...which implementation of the method should it use? Without any further clarification, it's impossible for the compiler to resolve the ambiguity.
Besides overriding, the other big problem with multiple inheritance is the layout of the physical objects in memory.
Languages like C++ and Java and C# create a fixed address-based layout for each type of object. Something like this:
class A:
at offset 0 ... "abc" ... 4 byte int field
at offset 4 ... "xyz" ... 8 byte double field
at offset 12 ... "speak" ... 4 byte function pointer
class B:
at offset 0 ... "foo" ... 2 byte short field
at offset 2 ... 2 bytes of alignment padding
at offset 4 ... "bar" ... 4 byte array pointer
at offset 8 ... "baz" ... 4 byte function pointer
When the compiler generates machine code (or bytecode), it uses those numeric offsets to access each method or field.
Multiple inheritance makes it very tricky.
If class C
inherits from both A
and B
, the compiler has to decide whether to layout the data in AB
order or in BA
order.
But now imagine that you're calling methods on a B
object. Is it really just a B
? Or is it actually a C
object being called polymorphically, through its B
interface? Depending on the actual identity of the object, the physical layout will be different, and its impossible to know the offset of the function to invoke at the call-site.
The way to handle this kind of system is to ditch the fixed-layout approach, allowing each object to be queried for its layout before attempting to invoke the functions or access its fields.
So...long story short...it's a pain in the neck for compiler authors to support multiple inheritance. So when someone like Guido van Rossum designs python, or when Anders Hejlsberg designs c#, they know that supporting multiple inheritance is going to make the compiler implementations significantly more complex, and presumably they don't think the benefit is worth the cost.
Solution 2:
The problems you guys mention are not really that hard to solve. In fact e.g. Eiffel does that perfectly well! (and without introducing arbitrary choices or whatever)
E.g. if you inherit from A and B, both having method foo(), then of course you don't want an arbitrary choice in your class C inheriting from both A and B. You have to either redefine foo so it's clear what will be used if c.foo() is called or otherwise you have to rename one of the methods in C. (it could become bar())
Also I think that multiple inheritance is often quite useful. If you look at libraries of Eiffel you'll see that it's used all over the place and personally I've missed the feature when I had to go back to programming in Java.
Solution 3:
The diamond problem:
an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C. If there is a method in A that B and C have overridden, and D does not override it, then which version of the method does D inherit: that of B, or that of C?
...It is called the "diamond problem" because of the shape of the class inheritance diagram in this situation. In this case, class A is at the top, both B and C separately beneath it, and D joins the two together at the bottom to form a diamond shape...
Solution 4:
Multiple inheritance is one of those things that is not used often, and can be misused, but is sometimes needed.
I never understood not adding a feature, just because it might be misused, when there are no good alternatives. Interfaces are not an alternative to multiple inheritance. For one, they don't let you enforce preconditions or postconditions. Just like any other tool, you need to know when it is appropriate to use, and how to use it.