Multiple Inheritance – Why Reduce Multiple Inheritance to the Diamond Problem?

class-diagrammultiple-inheritancenaming

Whenever I read something like this:

Many programmers exhibit a slight, involuntary shudder whenever
multiple inheritance is mentioned. Ask them to identify the source of
their unease and they will almost certainly finger the so-called
Deadly Diamond of Death inheritance pattern. In this pattern, classes
B and C both inherit from class A, while class D inherits from both B
and C. If B and C both override some method from A, there is
uncertainty as to which implementation D should inherit.

enter image description here

I cannot come back and not to ask: why do you reduce multiple inheritance problem to the Diamond problem? Do you understand that problem is the name conflict that stems from convergence of classes, rather than their reconvergence (diamond)? You do not need the common root A class/interface for the naming conflict to happen, as the diagram shows

enter image description here

It is MI which enables the class convergence and, thus, naming conflicts, which are the problem we are talking about. Why do you pff like it is not the case and keep calling it a diamond problem rather than MI problem?

Best Answer

You're partially right: the problem exists in the case of the multiple inheritance too, but can easily be solved in some languages; diamond, on the other hand, cannot be solved that easily.

In C#, multiple inheritance is forbidden, but a class can implement multiple interfaces. Imagine that the class Example implements IModifiable and ITransformable. Those two interfaces have both a method Transform(string) : string. How would you implement this?

public class Example
{
    public string IModifiable.Transform(string value);
    public string ITransformable.Transform(string value);
}

This means there is no ambiguity. You have not one, but two methods with clearly distinct signatures.

Now, imagine the diamond case:

public abstract class Parent
{
    public abstract void DoSomething(string value);
}

public class Child1 : Parent
{
    public override void DoSomething(string value)
    {
        // Do something here.
    }
}

public class Child2 : Parent
{
    public override void DoSomething(string value)
    {
        // Do a completely different thing.
    }
}

public class Example : Child1, Child2
{
}

Now, when we call the method DoSomething on Example, we actually want to invoke the method declared in Parent. So how would the runtime decide which one of the implementations to run?