Tuesday, September 20, 2011

Luke, who's your father - multiple interface implementation in C#

Multiple inheritance - this strange and gruesome beast

Multiple inheritance was practised in those dark, long gone days when c++ roamed the software world. Then the meteor of modern OOP languages struck, nearly wiping out the usage of c++ in enterprise software, and with it went multiple inheritance. We know of its existance from written record (early 90s programming textbooks, still in use in some parts of the world) and through archaeological reviews of some decades-old systems.

There is one remnant of multiple inheritance that is still present today, though - multiple interface implementation. In c# we don't have multiple inheritance and the complications associated with it (e.g. the diamond problem, which I call Luke, I am your father... twice) but it brings about another set of peculiarities.

First, there is the situation with duplicate member names but it's resolved relatively simply with explicit interface implementation. You can create a hierarchy like this one:

interface IBase1 { void DoBaseStuff();}
interface IBase2 { void DoBaseStuff();}
class Derived : IBase1, IBase2
{
public void DoBaseStuff() { }
}

You can implement both methods with one declaration, as in the example above, or alternatively - have explicit implementation and two different versions:

class Derived : IBase1, IBase2
{
void IBase1.DoBaseStuff() { }
void IBase2.DoBaseStuff() { }
}

Hell, you can even combine both and provide a native implementation on top of the two explicit interface implementations:

public void DoBaseStuff() { }
void IBase1.DoBaseStuff() { }
void IBase2.DoBaseStuff() { }

so you can then call the three different implementations like this:

Derived derived = new Derived();
derived.DoBaseStuff();
((IBase1)derived).DoBaseStuff();
((IBase2)derived).DoBaseStuff();

Turning to the dark side

All this is just for starters and is explained in every decent .NET book (I hope we have it in the one I co-wrote - it would be ironic if we don't). Now let's get to the more interesting stuff.

One can easily reproduce the Luke I'm your father twice situation using just interfaces, the following thing compiles:

interface IVader {
void TurnToTheDarkSide();
}
interface ISomething1 : IVader { }
interface ISomething2 : IVader { }
class Luke : ISomething1, ISomething2
{
public void TurnToTheDarkSide() { }
}

However, this is much easier to deal with compared to real multiple inheritance as we haven't been to provided the means to code separate implementations for ISomething1.TurnToTheDarkSide() and ISomething2.TurnToTheDarkSide() - we can only have a single body for this method and it will be executed no matter if we access the object through a Luke, ISomething1 or ISomething2 pointer. The only bit of fun we can have is to provide an own implementation in the class:

public void TurnToTheDarkSide() {
Console.WriteLine("Luke, I'm your own implementation");
}
void IVader.TurnToTheDarkSide() {
Console.WriteLine("Luke, I'm your derived interface implementation");
}

In this case we'll have one method for calls originating from a Luke pointer and another one when calling through any of the interfaces, e.g. this code:

Luke luke = new Luke();
luke.TurnToTheDarkSide();
((ISomething1)luke).TurnToTheDarkSide();
((IVader)luke).TurnToTheDarkSide();

will produce the following:

Luke, I'm your own implementation
Luke, I'm your explicit interface implementation
Luke, I'm your explicit interface implementation

And that's it - in .NET we can't have separate implementations for the two Vaders, even through explicit interface implementation, that's a feature of the framework intended to spare us some of the complexities.

Dealing with dark explicit implementations

Now let's see if there are some practical implications to this. Suppose that a we have a bunch of Jedi will eventually be politely asked by a Sith lord to join the dark side. We might model the situation with something like:

interface IJedi {
void TurnToTheDarkSide();
}
class Vader : IJedi
{
void IJedi.TurnToTheDarkSide()
{
Console.WriteLine("- Sure, why not. It can prevent death, right?");
}
virtual public void TurnToTheDarkSide()
{
Console.WriteLine("- Sweet, it does lightnings, doesn't it?");
}
}

class Luke : Vader//, IJedi
{
public override void TurnToTheDarkSide()
{
Console.WriteLine("- Never!");
}
}

then test it with:

Luke luke = new Luke();
Console.WriteLine("- Luke, turn to the dark side!");
luke.TurnToTheDarkSide();
Console.WriteLine("...");

Console.WriteLine("- Luke, turn to the dark side!");
((Vader)luke).TurnToTheDarkSide();
Console.WriteLine("...");

Console.WriteLine("- Luke, turn to the dark side!");
((IJedi)luke).TurnToTheDarkSide();

and see the result...

- Luke, turn to the dark side!
- Never!
...
- Luke, turn to the dark side!
- Never!
...
- Luke, turn to the dark side!
- Sure, why not. It can prevent death, right?

Oops, we lost Luke!
It looks like something dark from his father still lives in him, and revealing it is as easy as calling Luke through an IJedi interface, i.e. exactly the thing we'll do if we need to check a collection of Jedis - we'll poll them polymorphically through the IJedi interface. That's because Vader is so evil that he's provided both own and explicit interface implementation - in this case whichever derived class we address through an IJedi pointer it will always have a tendency towards the dark side.

So is there a way to save Luke? Fortunately, it turns out that there is one, and the answer is hidden in the commented out implementation of the IJedi interface by the Luke class. To fight the dark side, Luke needs to implement IJedi in his own right, and only then he will be able to silence the explicit interface implementation of his father.

I suspect that there are people who'll either find the examples too abstract or simply don't care enough for the future of the galaxy to accept this as an important real-world example. These people should consider the following situation - we're deriving from a class that implements IDisposable, but in our derived class we need to implement some completely different disposal logic, e.g. we might need to keep some resources for longer than the base class disposal logic dictates. Then, we throw an instance of our class to some closed-source framework that does (obj as IDisposable).Dispose(). Our natural step is to override Dispose() and expect our implementation to be executed - but no, the bastard that coded the base class (also closed source) decided to do both own and an explicit interface implementation of Dispose(). In this case our only option seems to be to implement the interface directly ourselves.

A similar situation might arise if we are deriving from some class and then need to serialize objects with some serializer that we don't have control over. If the base class author implemented both ISerializable.GetObjectData and own GetObjectData then we don't have control over how our derived class will get serialized if the call to GetObjectData is made through an ISerializable pointer.

As a conclusion, I'd like to stress that I'm not a huge Star Wars fan but I just thought that the story gives us a good context to portray the problem at hand. Further, they deserve at least a bit of praise for what they just did to the BT Tower.

I hope this helped you on your way to enlightenment. May the force be with you!

No comments: