A couple of days ago I posted on Implementation Classes as a viable solution for most Multiple Inheritance benefits without actually having Multiple Inheritance. I feel very strongly that Microsoft should make Implementation Classes or something equivalent a direct part of the C# 4.0 and VB 10 languages (given that it won’t happen in Orcas).
I think this would be one of the most important language developments that could ever happen in .NET.
It would eliminate all of the annoying copy-and-paste code involved in implementing multiple interfaces and pointing them back to true objects to gain most of the benefits of Multiple Inheritance. Plus it would settle most of the calls for true MI and still satisfies the anti-multiple-inheritance camp.
Best of all, Microsoft can easily (and I stress easily) do this with compiler wizardry given that it really isn’t a huge amount of work (just very tedious) to do it manually. If Microsoft can come up with compiler solutions for Generics, LINQ, Extension Methods, and Dynamic Typing then there is no reason to make major changes to the CLR for Implementation Classes.
So what could it look like syntactically? There are a few different thoughts on this and Anders Hejlsberg would certainly have something to say about this... at least for the C# camp. Let's take a look:
Implementation Classes
This is my take on it, although most of it has been liberally borrowed from other sources, to the authors of which I am eternally grateful.
The trick is to create one or more special “Implementation Classes” that each provides strong implementation for one or more of the desired interfaces. Suppose we had the following interface:
public interface IEditableObject
{
void BeginEdit();
void CancelEdit();
void EndEdit();
}
That’s not so hard to imagine because it does exist in the .NET Framework. If we want to use this interface in the exact same way with the exact same code for multiple classes then we would start by creating an “Implementation Class called EditableObject:
public implementation class EditableObject : IEditableObject
{
public EditableObject ()
{
// ... Constructor Could Contain Parameters
}
// ... Some Private Member Variables
// (Probably a Key/Object Pair)
// To Hold The Values Of Different Properties and Fields
// Captured During BeginEdit()
void System.ComponentModel.IEditableObject.BeginEdit()
{
// ... Use Reflection To Store Current Values
}
void System.ComponentModel.IEditableObject.CancelEdit()
{
// ... Use Reflection To Write Back Values
// Captured in BeginEdit()
}
void System.ComponentModel.IEditableObject.EndEdit()
{
// ... Clear Values Captured in BeginEdit()
}
}
Notice the implementation keyword. First of all, it would prevent the class from being instantiated directly, similar to the way that abstract does:
// The following line would not compile
EditableObject e = new EditableObject();
More importantly, this would tell the compiler that this is an implementation class. When another class “inherits” it, the inheritance wouldn’t be your standard, garden-variety of inheritance. Consider the Product class:
public class Product : EditableObject
{
}
When this compiles, it would not compile to a standard inheritance relationship. Instead, the MSIL produced would be equivalent to if we had written the following:
public class Product : System.ComponentModel.IEditableObject
{
EditableObject _EditableObjectImplementation;
void System.ComponentModel.IEditableObject.BeginEdit()
{
_EditableObjectImplementation.BeginEdit();
}
void System.ComponentModel.IEditableObject.CancelEdit()
{
_EditableObjectImplementation.CancelEdit();
}
void System.ComponentModel.IEditableObject.EndEdit()
{
_EditableObjectImplementation.EndEdit();
}
}
Here I have chosen to use explicit interface implementation. That makes a great deal of sense because typically we would pass a Product object to a method expecting a reference to an IEditableObject interface. We wouldn’t usually want to directly call BeginEdit() from a Project object. For implicit interface implementation, I would simply add an implicit keyword:
public class Product : EditableObject implicit
{
}
This would produce MSIL equivalent to:
public class Product : System.ComponentModel.IEditableObject
{
EditableObject _EditableObjectImplementation;
public void BeginEdit()
{
_EditableObjectImplementation.BeginEdit();
}
public void CancelEdit()
{
_EditableObjectImplementation.CancelEdit();
}
public void EndEdit()
{
_EditableObjectImplementation.EndEdit();
}
}
Obviously _ EditableObjectImplementation needs to be instantiated in the constructor so that some poor consumer of a Product object doesn’t get the dreaded null reference exception. It could be handed in a similar way to the call to base() in C# and done by using the Implementation Class’ name:
public Product()
: base(), EditableObject()
{
}
This would compile to MSIL as if we had written:
EditableObject e = new EditableObject();
As previously stated, we wouldn’t be able to actually make the above call ourselves. If more than one implementation classes where consumed by the Product class then they should appear in the order of instantiation:
public Product()
: base(), EditableObject(), Clonable()
{
}
Parameters could be passed to each Implementation Class’ constructor if needed. Another approach would be to require the instantiation to be done within the body of the Product class’ constructor. The most flexible would be to allow the instantiation to occur anywhere in constructor body:
public Product()
: base()
{
// ... Code Here ... //
EditableObject();
Clonable();
// ... Code Here ... //
}
This gives maximum flexibility to accomplish everything that you can already do but without having to write tedious and identical plumbing over and over and over again. If an instantiation call is not invoked in the constructor body then it should be done automatically by the compiler at the beginning of the constructor.
Remember, this type of thing is already possible if you do it manually; all I’m doing here is proposing my version of the syntactic sugar that IntelliSense and the compiler could give us to make it easier and less typo-prone.
Now let’s look at someone else’s idea:
Implicit Interface Implementation through Aggregation
While searching through Microsoft’s product feedback center for other Multiple Inheritance and Default Interface Implementation sympathizers, I came across a great idea posted by Dmitry Kolchev.
See (and vote on) this wonderful idea at:
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94304
We will keep the same example as above as far as creating the EditableObject class (with the removal of the factious “implementation” keyword in the class definition). Dmitry’s Product class would look like this:
public class Product : System.ComponentModel.IEditableObject
{
EditableObject _EditableObjectImplementation provides IEditableObject;
}
Here he is proposing a new keyword called “provides” to tell the compiler to create a member definition within Product for each of IEditableObject’s members and to point them straight back at the _EditableObjectImplementation object’s corresponding member. In essence, the compiler would be adding MSIL equivalent to if we had typed in:
public class Product : System.ComponentModel.IEditableObject
{
EditableObject _EditableObjectImplementation;
public void BeginEdit()
{
_EditableObjectImplementation.BeginEdit();
}
public void CancelEdit()
{
_EditableObjectImplementation.CancelEdit();
}
public void EndEdit()
{
_EditableObjectImplementation.EndEdit();
}
}
That is the same equivalent code as my Implementation Classes idea but Dmitry has gone about the definition syntax a differently. To change between implicit and explicit implementation Dmitry has also proposed the keywords “implicit” and “explicit”, although it isn’t stated where they would be placed. My guess would be after “provides”.
Also, the developer gets full control over how and when the _EditableObjectImplementation field is instantiated, which is the most flexible. Of course, if the developer doesn’t do that then they end of up with a null reference exception. The existing compiler warning will probably be enough to help most programmers and this isn’t really an issue.
Default Interface Implementation
Some folks are after Default Interface Implementation, in which interface definitions members have code in them and if you don’t “override” that member when you implement the interface then the code in the interface is used by default.
Several years ago I thought this was a good idea but I have come to realize that it would be completely useless in the vast majority of cases. Each solution has very different needs and the chances of a 1-size-fits-all solution for an interface implementation are incredibly slim.
We must have the ability to create different “default” behaviours for the same interface because your needs are different from my need and my needs in Project ABC are different than my needs in Project XYZ. Default Interface Implementation in which the code is together with the interface just doesn’t offer this.
Summary
I’m always been one to look for the best solution and I must say that I really like Dmitry’s solution. For one thing, it really clarifies that there is a big difference between inheritance and interface implementation.
That’s something that I really like about VB – it uses the Inherits keyword for inheriting and the Implements keyword for interface implementation whereas C# makes it all look like inheritance. Granted, C# is my language of choice in part because of its slim syntax but I think that every Introduction to OOP course should be taught with VB.NET because of its clear syntax.
So, Microsoft, if you’re listening: Dmitry’s idea here is fantastic and you should probably implement Default Interface Implementation this way if you don’t want the anti-Multiple-Inheritance camp up in arms. Plus it just makes a huge amount of sense. If you want to half-fake MI, go with my idea. If you want to fully-fake MI, go with what Eiffel# does. The MSIL that would be generated is the same no matter what the syntax.
Regardless of how it is done, I feel very strongly that this would benefits developers everywhere – especially those of us that are writing large frameworks. For now, we can still do it manually, albeit with a lot of tedium and copy-and-paste code. Here’s hoping Hawaii makes pseudo-MI a walk on the beach.
Happy Coding
- Shaun
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