posted on Wednesday, July 12, 2006 11:16 AM by shayward

Multiple Inheritance Solutions: Implementation Classes

Getting into discussions about Multiple Inheritance can be sticky things. Single-Inheritance-purists want the perfect object pyramid starting with object as the apex. They claim that it is cleaner - and they're right. How many “is a kind of” relationships can a class have?

But we must ask ourselves, "What problems are supposed to be solved by inheritance?" and then we must ask ourselves if our current or near-future system (let's say C# 3.0) solves them.

The solutions given by inheritance, as I see them and in no particular order, are:

  • Easy code reuse
  • Fix it in one place
  • Removal of code redundancy (no more copy-and-paste code)
  • Modeling real-world objects
  • Breaking large problems into small, manageable pieces
  • Pass a reference to the base class and use the same members, even though they are implemented totally differently (polymorphism)
  • Not knowing or caring how the code was implemented or being able to talk to it directly (encapsulation)

So does our current system in C# 3.0 (and VB 9.0) live up to these expectations? To some extent yes and to some extent no.

When We Need Multiple-Inheritance
Let's say that I want to create a layer filled with business classes like Employee, EmployeeCollection, Vendor, VendorCollection, and a couple of hundred others. Some of these should be clonable and some should not. Some of these should be editable with rollback capabilities and some should not. Some of these should be bindable and some should not. Some of these should be bindable collections and some should not.

For each of clonable, editable, bindable, and bindable collection we have the exact same code that we wish to apply everywhere. Plus we want to treat these objects the same in a clonable, editable, and bindable context regardless of what type of object they really are. Ideally, we could create 4 classes and inherit as many of which ever ones are needed for each situation.

But that would require Multiple Inheritance, which we can't have. We can just create a single, common base class because each business class needs a different combination of these functionalities. We are back to re-inventing the wheel for each one of these and using error-prone "copy-and-paste inheritance". There goes more than half of our inheritance benefits. So what good is inheritance if we can't actually use it?

The interesting thing here about these is that they are not examples of "is a kind of" relationships, as is commonly thought of with inheritance. After all, Employee isn’t a “kind of” Clonable or Editable or Bindable. All of these examples require "contracts for functionality", thus denoting interfaces.

Indeed, we have the interfaces IClonable, IEditableObject, annd IBindingList. Some, myself included, have created the IBindable interface for extending IEditableObject. But even if we use Interfaces we only gain semi-polymorphic benefits and we are still doomed to copy-and-paste code.

The Solution: Implementation Classes
The solution that I've been using is to create strong implementations of these interfaces and place them as private members in the class that I want to inherit them. The target class also implements the interface and exposes the various members of the private instances through it. For example:

   public class Clonable : ICloneable
   {
      public object Clone()
      {
         // ... Use reflection to determine 
         //     which class owns this instance
         // ... Use reflection and attributes 
         //     to produce the clone of the owner instance
      }
   }

   public class Employee : ICloneable
   {

      // Constructor that includes instanciating _Clonable

      private Clonable _Clonable;

      public object Clone()
      {
         return _Clonable.Clone();
      }
   }

While this is a simple example, the principal works with a whole host of interfaces. I've been using it very successfully to gain 99% of the benefits of MI without actually using MI.

I call these types of strong implementations, such as the Clonable class in this example, Implementation Classes. It's not a full class because it has no value on its own and it is just one possible, yet common, implementation of an interface.

Calling the Constructor
With inheritance, the base class’ constructor is called as the first command in the inheriting class’ constructor. With an Employee class, the constructor would look something like this:

   public Employee()
      : base()
      {
         // Constructor logic
      }

In VB.NET the call to the base class’ constrictor is the first line of code inside of the constructor body instead of a part of the constructor definition. In any event, the base class constructor is the first thing called when creating a new instance of the inheriting class.

With Implementation Classes, you must create the private instance that holds the functionality before you can use it. This should be done anywhere in the constructor body provided that nothing tries to use it before it is instantiated.

   public Employee()
   {
      // ... some statements ... //
      _Cloneable = new Cloneable();
      // ... some more statements ... //
   }

Parameterized constructors can be used as well, assuming the Implementation Class has one:

   public Employee(bool CloneDeep)
   {
      // ... some statements ... //
      _Cloneable = new Cloneable(CloneDeep);
      // ... some more statements ... //
   }

One could even delay the instantiation of the _Cloanble object until some point after the constructor has been called but this can be very dangerous because an outside object could call the Employee object’s Clone() method and generate a null reference exception.

Abstract (MustOverride) Members
Of course, Implementation classes can't really be like MI without the ability to create abstract members. The answer is in delegates.

The implementation class should create a delegate that matches the desired signature of the member. It should then create a field to hold a reference to the delegate. Finally, the "abstract member" should just invoke the referenced delegate.

   public delegate bool SomeAbstractMethodDelegate(string SomeParameter);

   private SomeAbstractMethodDelegate _SomeAbstractMethodInstance;

   public bool SomeAbstractMethod(string SomeParameter)
   {
      return _SomeAbstractMethodInstance.Invoke(SomeParameter);
   }

Since this is an abstract method and should be "overridden" before any functionality takes place, the best place to pass the delegate would be in the constructor.

If you were looking for a dynamically-overridable method that could change at any moment you could just wrap the _SomeAbstractMethodInstance field into a read/write property and throw an exception if someone tried to set it to null. This does, however, give the programmer enough rope to hang themselves and every member of their IT department.

Virtual (Overridable) members can be handled in a similar way but would require some extra plumbing to be able to call the original vs. the overridden version, as can be done with true inheritance.

The Benefit
What benefits do we really gain by using the concept of Implementation Classes? Now, instead of copying and pasting the full implementation of an interface over and over and over again, you only have to:

  • Build the implementation class once based on an interface
  • Create a private member instance of the Implementation class
  • Add ": [InterfaceName]" to the end of your "inheriting" class
  • Paste a block of code that simply implements the interface members by calling the private implementation object's member of the same name

I have a very large project with classes that each implements some of a dozen different interfaces in the exact same way. Since each class implements a different number and variety of these interfaces, creating a base class for all of them is not an option. Implementation Classes have largely given me back the benefits of Multiple Inheritance and they have given me back my sanity. Best of all, they don’t really violate any rules of inheritance.

There still is some copy-and-paste code, which causes me grief, but it is greatly reduced and it is much easier to debug the entire solution.

Where does this leave us?
At the end of the day, this still doesn't give us Multiple Inheritance and it still doesn't eliminate all of the redundant copy-and-paste inheritance that must be done with interfaces. But it does give the benefits of easy code reuse, fix it in one place, far less copy-and-paste code, elimination of copy-and-paste of critical code, and it allows us to further break the problem into smaller, manageable pieces.

It also underscores the fact that there are two types of inheritance: "Is a kind of" and "constrict for functionality". MI often boils down to wanting multiple contracts for functionality with the actual functionality in tact. Implementation Classes deliver just that.

Happy Coding
- Shaun


Comments

# re: Multiple Inheritance Solutions: Implementation Classes

Sunday, July 01, 2007 11:45 PM by Diego
I think your raise some interesting issues about MI in your blog. I like the idea of combining interface inheritance with implementation composition the way you describe.

I also think it would be nice to have something like the "provides" keyword as syntactic sugar to get the compiler to write all the delegates for us. One little detail about this, is that it would probably raise the need for another keyword to do method renaming (the way it is done in Eiffel).

I want to add my thoughts about an aspect I think deserves more consideration: the population of the implementation “providers”:

In your examples, you seem to hardcode the implementation classes (i.e., there is an EditableObject member in your Product class, and not an IEditableObject member). But in my experience this is very often a “configuration point”: You may want let your client code, a configuration file, or even your database, decide which concrete implementation class to instantiate and plug to your Product instance.

I think you could be very interested in what an inversion of control container such as Windsor could do for you. Given your Product class with an IEditableObject member and some configuration, an IoC could decide which IEditableObject implementation class to instantiate and inject at run-time.

An alternative would be to use an intermediate locator object. This is what I use more often for implementing the Strategy Pattern. In this case, instead of declaring an IEditableObject member directly, I would declare a StrategyLocator<IEditableObject> editable member. I could elaborate much more on this, but I guess this is a little off topic.