2008/03/19

Emulating MixIns with C#

One of the shortcomings of C# is the missing support of MixIns, which are a popular substitute for multiple inheritance especially in Ruby. MixIns provide a way to put a common functionality in a separate classand use it in another class. That is still easy in C#, one can simply use inheritance. But, what will you do, when your classes are already inheriting from other classes? You won't want to break up your inheritance hierarchie for this, will you? Using a MixIn, you can put a common functionality in a separate class and mix it into multiple classes, regardless of their inheritance hierarchy. The methods and properties of a MixIn-class are merged into the using classes' interface and can also use the original classes members. That's the theory and what is possible in Ruby, but can it be achieved in C#? If you need an example for MixIns, you might want to read the following blog post http://www.juixe.com/techknow/index.php/2006/06/15/mixins-in-ruby/. However, you don't need any Ruby knowledge for the remainder of my post. Ok, what are the characteristics of a MixIn again:
  1. Accessible via the using class
  2. Has access to the using class' instance members
  3. Must not use inheritance

Taking into account that C# is a statically and strongly typed compiled language, this is not possible at first glance. But, if all possibilities of C# are used, they can be fulfilled at least partially.

As an example, I will develop a MixIn that adds reduction-functionality to collections. Reduction is a functional programming concept means that the collection will be reduced (boiled down) to a scalar value using a user-specified delegate. Simple reductions are joining a collection of strings or adding up a collection of integers.

The following code shows how this can be implemented using a conventional static method:

    1 using System.Collections.Generic;
    2 
    3 namespace Example
    4 {
    5     public delegate TItem ReduceDelegate<TItem>(
    6         TItem firstItem, 
    7         TItem secondItem);
    8 
    9     public static class Reduction
   10     {
   11         public static TItem Reduce<TItem>(
   12             IEnumerable<TItem> collection, 
   13             ReduceDelegate<TItem> reduceFunction)
   14         {
   15             TItem result = default(TItem);
   16             bool first = true;
   17             foreach (TItem item in collection)
   18             {
   19                 if (first)
   20                 {
   21                     result = item;
   22                     first = false;
   23                 }
   24                 else
   25                 {
   26                     result = reduceFunction(result, item);
   27                 }
   28             }
   29             return result;
   30         }
   31     }
   32 }
Now the question is, how can this functionality be implemented as a mixin. We will need at least to interfaces for this:
  • An interface that allows the mixin access to the using class.
  • An external interface that allows a client to use the functionality provided by the mixins.

The code below shows how these are declared:

    1 namespace Mixin
    2 {
    3     public delegate TItem ReduceDelegate<TItem>(
    4         TItem firstItem, 
    5         TItem secondItem);
    6 
    7     public interface IReduceClient<TItem> : IEnumerable<TItem>{}
    8 
    9     public interface IReduceMixin<TItem>
   10     {
   11         TItem Reduce(ReduceDelegate<TItem> reduceFunction);
   12     }
   13 
   14     public interface IWithReduce<TItem> : IReduceClient<TItem>, IReduceMixin<TItem> {}
   15 
   16     public class ReduceMixin<TItem> : IReduceMixin<TItem>
   17     {
   18         public ReduceMixin(IReduceClient<TItem> client)
   19         {
   20             this.client = client;
   21         }
   22 
   23         private readonly IReduceClient<TItem> client;
   24 
   25         public TItem Reduce(ReduceDelegate<TItem> reduceFunction)
   26         {
   27             TItem result = default(TItem);
   28             bool first = true;
   29             foreach (TItem item in client)
   30             {
   31                 if (first)
   32                 {
   33                     result = item;
   34                     first = false;
   35                 }
   36                 else
   37                 {
   38                     result = reduceFunction(result, item);
   39                 }
   40             }
   41             return result;
   42         }
   43     }
   44 }

Line 7 declares the interface that the mixin uses to access the using class (IReduceClient). This can be arbitrary complex, but in this case, we only need an enumeration, so I just inherited from IEnumerable. Line 9 declares the interface that is publicly used to access the mixin's functionality (IReduceMixin). IWithReduce on line 14 just brackets the other two interfaces, so that an using class can specify IWithReduce, which shows the intention better than using the two different interfaces.

The mixin class is shown on lines 16ff. It simply holds a reference to the client, a.k.a. the using class and the Reduce implementation shown above.

Now the problem is how can the mixin added to a client. The code below would be ideal, but won't work with C# 2.0:

    1 namespace Client
    2 {
    3     public class ReducableList<T> : List<T>, IWithReduce<T>
    4     {
    5         // Won't work that way!
    6     }
    7 }

Before I show a (naive) implementation, here is the test code for the whole thing, that shows how it is used:

    1 namespace Test
    2 {
    3     [TestFixture]
    4     public class ReduceTest
    5     {
    6         [Test]
    7         public void TestMixin()
    8         {
    9             ReducableList<string> rl = new ReducableList<string>();
   10             rl.AddRange(new string[] {"a", "b", "c"});
   11 
   12             IReduceMixin<string> reducable = rl;
   13             Assert.AreEqual("a,b,c", reducable.Reduce(delegate(string s1, string s2) { return s1 + "," + s2; }));
   14 
   15             ReducableList<int> rli = new ReducableList<int>();
   16             rli.AddRange(new int[] {1, 2, 3, 4});
   17             Assert.AreEqual(10, rli.Reduce(delegate(int i, int j) { return i + j; }));
   18         }
   19     }
   20 }

R# Jedi

One simple, naive and somewhat cheating method to make the ReducableList work, is using ReSharper. Just add a IRecudeMixin field and choose Alt+Ins/Delegate members. As a finishing touch you need to initialize the field.

The resulting code is shown below:

    1 namespace Client
    2 {
    3     public class ReducableList<T> : List<T>, IWithReduce<T>
    4     {
    5         public ReducableList()
    6         {
    7             reducer = new ReduceMixin<T>(this);
    8         }
    9 
   10         // Other constructors omitted for brevity
   11 
   12         private readonly ReduceMixin<T> reducer;
   13 
   14         public T Reduce(ReduceDelegate<T> reduceFunction)
   15         {
   16             return reducer.Reduce(reduceFunction);
   17         }
   18     }
   19 }

Well, I know that this is not a viable solution for maintainable software, but it is at least a quick fix and an introduction for the next article, which will show how to use DynamicProxy2 for creating a ReducableList without ReSharper Jedi.

2 comments:

Stefan Papp said...

Very good article.

You might be interested that now there is an open source library available on codeplex that brings mixins to .NET

For more information checkout http://remix.codeplex.com

Thank you!

Stefan Papp said...

Very good article.

You might be interested that now there is an open source library available on codeplex that brings mixins to .NET

For more information checkout http://remix.codeplex.com

Thank you!