Wednesday, July 9, 2008

C# Mixins

Update: Corrected terminology – it’s “generic functions” not “generic methods”.

Aside from macros, another nice feature that Lisp supports is mixins. In fact, this is one of the (very, very) few things I miss about C++. Of course, Lisp does it in a much more powerful way using something called generic functions. See here and here for a great description of generic functions in Common Lisp – it’s one of the cooler parts of Lisp, in my opinion, especially for someone like me who has come from a C++/C#/Java OO background.

Although not a tool for every occasion, and somewhat against the spirit of Inherit to Be Reused, Not to Reuse, mixins are nonetheless handy at times. Since mixins are generally implemented via multiple inheritance, they haven’t really been an option in C#…until extension methods came along. Now you can do something like this:

using System;

public interface TellNameMixin
{
    string Name { get; }
}

public static class MixinImplementation
{
    public static void TellName(this TellNameMixin subject, string prefix)
    {
        Console.WriteLine("My name is: {0}{1}", prefix, subject.Name);
    }
}

What we’ve done is to define an interface type and a corresponding extension method that adds functionality to that interface. Since any number of interfaces can be implemented on a type, we can apply our mixin to classes that have no other type relationship, or that already have a base class. Like this:

public class Craig : MarshalByRefObject, TellNameMixin
{
  public string Name { get { return "Craig"; } }
}

public class Program
{
  public static void Main()
  {
     Craig craig = new Craig();
     craig.TellName("Mr. "); // Prints “Mr. Craig”
  }
}

The best part about this is – as with all reuse mechanisms – there’s only one place where I have to change how TellName works. Obviously, if the Craig class was the only class I was extending, I could skip the mixin class and just use extension methods directly. But if I have additional types that I want to add this functionality to, and if those classes have no other type relationship (a situation I found myself in just today) then this might be handy.

Anyway, it’s not something you’ll use every day, but it’s worth knowing about.

11 comments:

  1. Just a minor nit...in Common Lisp, they're called generic functions. Methods are something different (they're contained within the GFs.)

    ReplyDelete
  2. The funny thing is, as I was writing this, I kept typing "generic functions" and then "correcting" it. Guess I should have gone with my gut. Or looked it up. :)

    ReplyDelete
  3. I don't think mixins are against the spirit of "Inherit to be reused, not to reuse". Done correctly (ala Ruby et al), mixins are a very nice was to get reuse without actually changing your inheritance tree. The mixed in methods in a language like Ruby become YOUR methods and not something you get via inheritance.

    ReplyDelete
  4. Pingback from Reflective Perspective - Chris Alcock » The Morning Brew #133

    ReplyDelete
  5. @Peter: so in your opinion, in languages that support multiple inheritance, reuse is a reasonable use for inheritance? I would tend to agree...and it's yet another reason I've never liked the single inheritance restriction of .NET.

    ReplyDelete
  6. Mixins based on extension methods are cool, but they are also somewhat restricted. For example, storing state on a per-instance basis is difficult - you need to use a dictionary-based approach, but deal with WeakReferences and stuff to avoid keeping objects alive. Mixins based on extension methods cannot introduce additional interfaces to a class. In contrast to C++ mixins, they cannot override base class methods, and target classes cannot override mxin methods. And they can only access public (interface) members of the mixed type, not protected ones.

    So, mixins based on extension methods are definitely nice, and especially the compiler support is awesome. However, there are quite a few features they are missing, which is why we are working on a library called re:motion mixins here at my company. We did a presentation about it at Lang.NET in January [1], and there is a homepage: http://www.re-motion.org/. The latter is, however, terribly out of date, since we are working very hard on getting our first open source release of the framework out of the door. But at least one can download a preview version.

    Fabian

    [1] http://langnetsymposium.com/talks/2-10%20-%20remotion%20Mixins%20-%20Stefan%20Wenig%20and%20Fabian%20Schmied%20-%20rubicon.html

    ReplyDelete
  7. You won't hear me argue that C# has every feature that I'd like. :)

    ReplyDelete
  8. Pingback from IList Performance Decrease « Tales from a Trading Desk

    ReplyDelete
  9. Bill Wagner suggested the same thing here http://msdn.microsoft.com/en-us/vcsharp/bb625996.aspx
    So did John Rusk here http://dotnet.agilekiwi.com/blog/2006/04/extension-methods-solution.html.
    Scala supports traits/mixins naturally http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-5

    ReplyDelete
  10. remotion mixins is a library for bringing mixin technology to .NET probably the most comprehensive and elaborate in the industry (challengers welcome). The remotion mixins library can be used independently from remotion Home. And like remotion,...

    ReplyDelete
  11. re-mix is the open source library Fabian was mentioning and it has now been released.

    Check out http://remix.codeplex.com for more information

    ReplyDelete