J
Jan Van der Haegen
Guest
- Disclaimer:
First things first, a word of caution. Multiple inheritance is not possible in C#, and there's a good reason for it. I just wrote up this post to share some code and some ideas I had, you're absolutely free not to like it and not to use it. I'm not even claiming this idea is the "answer to all of life's problems", or even "useful to you in any way". And I'm absolutely not trying to defend the idea of multiple inheritance. However as usual, any constructive critique, additions, thoughts, ... are more then appreciated. Please don not assume the code samples (tight coupling, bad naming, ...) are in any way representative for the way I write code. They just help me demonstrate the idea.
If you like this work, feel free to click the "was helpful" button, free credit towards my fourth star on the MSDN forums is always appreciated.
- Why use implicit composition?
Junior year of college, just getting started into OOP, we've all learned about inheritance. It's great, but there are many pitfalls.
Lets have a look at some sample code, nothing too fancy...
public interface IPushable { void Push(); }
public class Pushable : IPushable { public void Push(){ Console.WriteLine("Pushed a pushable!"); } }
public class Button : Pushable
{
public Button() : base() { }
}
class Program {
static void Main(string[] args) {
Button button = new Button();
TryPushingIt(button);
Console.ReadKey(true);
}
static void TryPushingIt(IPushable pushable) { pushable.Push(); }
}
Nothing too fancy here, there's an interface IPushable, a basic implementation Pushable, and a little testprogram. The program creates a new Button, and passes it to the TryPushIt method. This works because Button IS a Pushable. (Inheritance).
Not too soon after, the inheritance design you used gets improved when you learn about composition. The sample code above could (should) be rewritten to use composition like this:
public interface IPushable { void Push(); }
public class Pushable : IPushable { public void Push(){ Console.WriteLine("Pushed a pushable!"); } }
public class Button : IPushable {
public Button() : base() { }
private IPushable pushable = new Pushable();
public void Push() { this.pushable.Push(); }
}
class Program{
static void Main(string[] args) {
Button button = new Button();
TryPushingIt(button);
Console.ReadKey(true);
}
static void TryPushingIt(IPushable pushable) { pushable.Push(); }
}
Still nothing new here (hopefully), there's an interface IPushable, a basic implementation Pushable, and a little testprogram. The program creates a new Button, and passes it to the TryPushIt method. This works because Button HAS a Pushable, and forwards the method calls to it. (Composition).
However, having done this kind of composition a thousand times and more, I'm getting kind of fed up with the amount of (what I call) boiler template code, required to make the composition work, which was not required when using inheritance. For clarity, I'm talking about this code being added to my Button class:
private IPushable pushable = new Pushable();
public void Push() { this.pushable.Push(); }
Sure in our example, Button is composed out of just one part (Pushable), and has just one method call to forward (Push). However, classes can be composed out of multiple parts, each with a couple of methods, quickly increasing the amount of boiler template code. More code not only means more work to make it work, but also more chance to introduce bugs by subtle typing errors (especially when the composed parts have methods that are heavily overloaded, being dyslectic, speaking out of personal experience here).
That's the problem, I was trying to solve...
- So what is implicit composition?
Playing around a bit, trying to find a way to reduce the amount of code needed to do composition, I've come up with this base class, using generics to replace the boiler plate code I mentioned.
public class ImplicitlyComposed<T>{
private T t;
public ImplicitlyComposed(T t) { this.t = t; }
public static implicit operator T(ImplicitlyComposed<T> comp) { return comp.t; }
}
The class consist out of a composition part (the first two lines), and an implicit cast from the class to the composed part. (Hence the name: Implicit Composition).
Let's rewrite our code sample to use this base class...
public interface IPushable { void Push(); }
public class Pushable : IPushable { public void Push(){ Console.WriteLine("Pushed a pushable!"); } }
public class Button : ImplicitlyComposed<Pushable> {
public Button() : base(new Pushable()) { }
}
class Program {
static void Main(string[] args) {
Button button = new Button();
TryPushingIt(button);
Console.ReadKey(true);
}
static void TryPushingIt(Pushable pushable) { pushable.Push(); }
}
Again, nothing really mind blowing in this code sample, there's an interface IPushable, a basic implementation Pushable, and a little testprogram. The program creates a new Button, and passes it to the TryPushIt method. This works because Button CAN BE CAST TO a Pushable. (Implicit Composition).
Because this cast is implicit, there's really not much code needed to compose Button out of a Pushable, only the declaration at the top ("Button : ImplicitlyComposed<Pushable>"), compared to the solution using inheritance, and there's substantially less code needed compared to the code sample using composition.
- But what about multiple composition?
Inheritance you can do, multiple inheritance is a no-no. (In c# that is.)
Composition you can do, and so is composing a class out of multiple parts.
When trying to reduce the code needed for composition, being able to support multiple parts is a requirement as well. Have a look at what I came up with to solve this:
public class ImplicitlyComposed<T> {
private T t;
public static implicit operator T(ImplicitlyComposed<T> comp) { return comp.t; }
public ImplicitlyComposed(T t) { this.t = t; }
}public class ImplicitlyComposed<T, U> : ImplicitlyComposed<U> {
private T t;
public static implicit operator T(ImplicitlyComposed<T, U> comp) { return comp.t; }
public ImplicitlyComposed(T t, U u) : base (u) { this.t = t; }
}
I have copy&pasted the base class ImplicitlyComposed, and added a new generic type to it. See how fast it is to expand our Button in the example to be composed of multiple parts:
public class Visualisable { public void Visualise() { Console.WriteLine("Visualized!"); } }
public class Pushable { public void Push(){ Console.WriteLine("Pushed a pushable!"); } }
public class Button : ImplicitlyComposed<Pushable, Visualisable> {
public Button() : base(new Pushable(), new Visualisable()) { }
}
class Program {
static void Main(string[] args){
Button button = new Button();
TryPushingIt(button);
TryVisualisingIt(button);
Console.ReadKey(true);
}
static void TryPushingIt(Pushable pushable) { pushable.Push(); }
static void TryVisualisingIt(Visualisable visualisable){ visualisable.Visualise(); }
}
Once again, I'm only required to change the class declaration "Button : ImplicitlyComposed<Pushable>" to "Button : ImplicitlyComposed<Pushable, Visualisable>", and I can pass my button as if it was a Pushable, as well as a Visualisable (as if I'm using multiple inheritance), while in fact Button has a Pushable and a Visualisable, and can be implicitly cast to either one.
- Any conclusions?
There's a lot of cons going for this implicit inheritance, like running into the issues as the inheritance diamond, and the fact that it can not be used with interfaces... (Yet...) So I would never use this in a public API as it is.
However, at the very least it's been a fun little idea to play with, and I'm currently doing a nice project where I'm actually enjoying using this very much...
public class ManageCustomerViewModel : ImplicitlyComposed < EntitySelectionViewModel<Customer>, SearchableViewModel<Customer>, AdditionalActionsViewModel<CreateNew<Customer>, ViewBalance, CreateInvoice>>>
The above code would be all that's needed to compose my ManageCustomerViewModel out of a list of customers, that can be filtered/searched, where new customers can be created, and for a selected customer, his/her balance can be viewed, or a new invoice can be created...
- Addendum 1:
The greatest flaw in my opinion, is the lack of support for interfaces, because it's not possible to create user defined conversions to and from interfaces... Help me improve my design here, and/or upvote this request if you agree with it.
- Addendum 2:
Here's the code for the five first ImplicitlyComposed classes. For your own library, feel free to add even more generic types...
public class ImplicitlyComposed<T>
{
private T t;
public static implicit operator T(ImplicitlyComposed<T> comp) { return comp.t; }
public ImplicitlyComposed(T t) { this.t = t; }
}
public class ImplicitlyComposed<T, U> : ImplicitlyComposed<U>
{
private T t;
public static implicit operator T(ImplicitlyComposed<T, U> comp) { return comp.t; }
public ImplicitlyComposed(T t, U u) : base (u) { this.t = t; }
}
public class ImplicitlyComposed<T, U, V> : ImplicitlyComposed<U, V>
{
private T t;
public static implicit operator T(ImplicitlyComposed<T, U, V> comp) { return comp.t; }
public ImplicitlyComposed(T t, U u, V v) : base(u, v) { this.t = t; }
}
public class ImplicitlyComposed<T, U, V, W> : ImplicitlyComposed<U, V, W>
{
private T t;
public static implicit operator T(ImplicitlyComposed<T, U, V, W> comp) { return comp.t; }
public ImplicitlyComposed(T t, U u, V v, W w) : base(u, v, w) { this.t = t; }
}
public class ImplicitlyComposed<T, U, V, W, X> : ImplicitlyComposed<U, V, W, X>
{
private T t;
public static implicit operator T(ImplicitlyComposed<T, U, V, W, X> comp) { return comp.t; }
public ImplicitlyComposed(T t, U u, V v, W w, X x) : base(u, v, w, x) { this.t = t; }
}
"The improbable we do, the impossible just takes a little longer." (Steven Parker)
Continue reading...