Introduction

Officially, Java and C# do not support true multiple inheritance (or “MI”). In other words, classes belong to a single-rooted object, and can inherit from only one parent class. Keep in mind that interfaces can still be inherited multiple times by a class. The reason Java and C# give for not supporting MI is that it is quite hard to implement in practice; in addition, it can (in some cases) manifest itself as an “anti-design pattern” and even cause the “diamond problem” (which I will explain later). It mostly boils down to the fact that MI usually introduces more complexity in the class hierarchy than it’s worth.

The lack of MI support in modern languages has forced programmers everywhere to write more organized, readable, and (most importantly) unambiguous code. Having said that, the usefulness of MI as a concept continues to be debated… especially considering other languages like Python and C++ support it!

First, I will explain how MI can cause ambiguity, and then I will show you how to simulate MI to actually reduce complexity in C#. Let’s get started!

Please note that this article assumes you have read my previous articles explaining topics on instantiation, public/private/protected methods, and interfaces.

Why the Lack of Support?

Remember that I mentioned the “diamond problem” earlier. Sometimes it is also referred to as the “dreaded diamond”. No matter what cute nickname you may have for it, the diamond problem is an ambiguity that arises when two classes (let’s call them B and C) inherit from another class (class A). In turn, class A needs to be inherited from class D, and there is a method in class A that either B or C override, but not D! In this confusing scenario, it’s hard to tell which version of method D should inherit: B‘s or C‘s?

Using more discrete examples, suppose you had a class Box that had the attributes Node and Transformable. In theory, both of these attributes would have a SetPosition method. Now you throw Drawable into the mix, which itself inherits from both of the above. The minute you cause Box to be inherited from Drawable, there will be an ambiguity – should this drawable box use Node‘s SetPosition method, or should it use Transformable‘s? Here’s some code to illustrate the example:

As you can see, there is ambiguity about which SetPosition method will actually end up being implemented. In C++, the compiler would spit out an error explaining the ambiguity, and you would need to insert virtual methods, or abstract methods with no implementation, in your classes. You would need to do this until there was only one method that could be implemented.

However, you can skirt around this issue in C# by simulating MI. This is because inheriting multiple interfaces doesn’t cause the aforementioned problem… since there can only be  one implementation of a method.

The above code example is also a good example of a use case, where you might want to use MI to reduce the complexity of a program.

How can MI be Simulated?

The following are several methods you can use to reasonably simulate MI in C#.

Method 1: Interfaces

As I previously mentioned, although C# doesn’t support inheriting from more than one parent class, it supports inheriting from multiple interfaces. Through interfaces, you can simulate MI and bypass the issues mentioned above. The previous example can be written as the following:

However, using the above method, you would have to implement all methods of Node, Transformable, AND Drawable in every class! This would result in a lot of duplicate code. To solve the issue, you could create an abstract class which implements the methods, and then inherit it to the main class.

What are the pro’s and con’s of such an implementation?

PROS:

  • Easy to implement
  • Generally recommended, since MI cannot cause the diamond issue

CONS:

  • Quite repetitive since code will need to be duplicated

Method 2: Has and Is

… What?

This refers to the fact that, sometimes, the properties and attributes you want to inherit have an “is” relation. Sometimes, they have a “has” relation.

A cat “is” an animal.
A horse “is” an animal.
Both cats and horses “have” legs.

Here’s how to illustrate the concept in code:

PROS:

  • This is the easiest way to simulate MI
  • There is no duplication of code

CONS:

  • It doesn’t have all the semantics of true MI
  • It is more difficult for humans to read, since a class usually doesn’t have another object in it (instead it should have a relation of the same object)

Method 3: Using Composition

This is an alternate version of Method 2. You can create a different composition to hold objects of classes you want to inherit. For example:

PROS:

  • Similar semantics to “true” MI

CONS:

  • A lot of “boilerplate” code
  • Difficult to manage in large programs

In Conclusion

Now you know the advantages of using MI in your programs. You can re-use code. You can have a collection of INode, ITransformable, IDrawable, etc. and take advantage of polymorphism and other programming paradigms (I promised myself I wouldn’t use that word…)

What is YOUR favorite way to implement MI in C#? Are you going to use MI in your library, or would you just prefer to leave it out altogether and use a different approach? Would you prefer to use delegates? Your feedback is appreciated!

Share

Comments are closed.

Post Navigation