Default Interface Member and Diamond Problem in Multiple Inheritance | C# 8
We know that C# does not support multiple class inheritance due to the diamond problem. Now since the interface can have default methodsin C#8, the million-dollar question is, how does it resolve the issue of the diamond problemin case ofmultiple inheritances. In this article, we will see how the .Net team has resolved the diamond problem in C# 8 for interfaces.
Why C# does not support the Multiple Class Inheritances?
How C# 8 overcomes the diamond problem in Multiple Interface Inheritance?
What is the most specific override rule in C# 8?
Introduction
A class in C# can only inherit from a single base class but can implement multiple interfaces. Until C# 8, only the base class could provide code that is usable by the derived class. With C# 8, interfaces can also provide usable default code to their implementing classes. But this may cause a diamond problem in multiple interface inheritances as well as class. But the Microsoft .Net team solved the problem, let's see how?
When any entity (class or interface ) inherit from more than one base entity (class or interface), it is called multiple inheritances.
So if a class has inherited from more than one base class, then it is called multiple class inheritance. Similarly, when an interface extended from more than one base interface, then it is called multiple interface inheritance.
Multiple Inheritance
What is the Diamond Problem?
The diamond problem is an ambiguity that can arise because of allowing multiple inheritances. It is a big problem for languages that allow multiple inheritances of states like C++. Multiple inheritances are not allowed for classes in C#, however, it is allowed for interfaces in a limited way so that it does not contain any state (instance field).
Diamond Inheritance Problem
Why C# does not support the Multiple Class Inheritances?
C# does not support it because it adds too much complexity to C#, one of them is the diamond problem. It will create ambiguity for CLR which one has to call if there is any method with the same name in more than one base class.
Example
How C# 8 overcomes the diamond problem in Multiple Interface Inheritance?
We know that C# 8 allows sharing code by default implementation, but interfaces are still not allowing to have instance fields (state).
Interface methods that require state either need to be abstract, so they are implemented in the class itself, or they need to accept the state as an argument provided by the caller. This approach avoids the inheritance diamond problem for the state.
On the other hand, the diamond problem of code is solved by the most specific override at runtime by the compiler.
In the above example. if you did not provide the definition for Display() in the inheriting class InheritingClass and InheritingClass2, then it will a generate a compile-time error:
"Interface member 'iBaseInterface.Display()' does not have a most specific implementation. Neither 'iDerivedInterface1.iBaseInterface.Display()', nor 'iDerivedInterface2.iBaseInterface.Display()' are most specific."
That makes sense actually because the Display() method has no default implementation in iBaseInterface. We must provide an implementation in the inheriting class InheritingClass to satisfy the compiler.
If the Display() method has any default implementation in iBaseInterface then we will never get any compiler error and we can skip if required the implementation of the Display() method in the inheriting class.
Every interface and class has a most specific override for every virtual member among the overrides appearing in the type or its direct and indirect interfaces.
The most specific override is a unique override that is more specific than every other override. If there is no override, the member itself is considered the most specific override.
The most specific override rule ensures that an ambiguity arising from a diamond inheritance is resolved explicitly by the programmer at the point where the conflict arises.
Since C# 8 support explicit abstract overrides in interfaces, so we could override the concrete implementation of base interface member to abstract in abstract classes as well like derived interface.
A class implementation of an interface member should always win over a default implementation in an interface, even if it is inherited from a base class. Default implementations are always a fallback only for when the class does not have any implementation of that member at all.
Override declarations allow the programmer to provide a most specific implementation of a virtual member in an interface where the compiler or runtime would not otherwise find one.
In the above example to avoid ambiguity, the most specific override rule will be applied. Hence, the Display() method of the inheriting class "InheritingClass" and "InheritingClass2" will be called.
Also, if you notice for InheritingClass3, the iDerivedInterface2's method is called because there is no definition in the inheriting class.
C# 8 supports multiple interface inheritance. The diamond problem is resolved by the most specific override rule in C# 8. In most specific override rules the class implementation of an interface member always wins.
Great Work !!
ReplyDeleteThank you very much.
DeleteYou can visit my Youtube channel for more interesting posts:
https://www.youtube.com/c/TechPointFundamentals?sub_confirmation=1