re-motion Team Blog

From the Team

Introducing mixins (finally)

without comments

Sorry for the delay. After lang.net I spent some time having fun with a bronchitis I caught there (I blame winter-season air conditioning). You can hear it in the talk too, but anyway, here we go.

In the last few months, we have developed a mixin mechanism for static .NET languages, which we’re using with C#. After a few months of internal dogfooding, we’re now ready to release it under an OSS license.

We believe that it provides several useful mechanisms for C# 2.0 and above today. Our mechanism is both powerful and easy to use, syntactically and semantically. We’re using it internally both for typical development problems that would traditionally require duplicate code in C#, as well as for componentized product line development.

Here’s a simple example:

[Uses (typeof (MyMixin))]
public class Target
{
}

public class MyMixin: IMyMixin
{
}

Target t = ObjectFactory.NewObject<Target>().With(); // With provides the constructor arguments 
IMyMixin m = (IMyMixin) t; 

All instances of the target type now implement the IMyMixin interface (as long as they are created via ObjectFactory).

The trick here is that mixins are in reality a composition mechanism, but implementing mixins feels more like inheritance. You define a mixin much like a subclass, and when you use the factory, a subclass is created that does all the composition for you. That gives you most of the power of multiple inheritance (and then some) without its specific problems, like diamond inheritance.

If the target type implements an interface, you can skip the casting by deriving what we call a “complete interface”. (Remember that whatever you might have heard about multiple inheritance, it’s generally assumed to be safe for interfaces.)

public interface ICompleteTarget: ITarget, IMixin {}
ICompleteTarget t = ObjectFactory.NewObject<ICompleteTarget>().With(); 

This is a general property of re:motion mixins: Everything works a bit smoother if you’re using interfaces a lot, but you can always work around it if that is not the case.

Here’s an advanced (if somewhat contrived) example:

public class Target: ITarget
{
  public Target (string name) {...}
  public virtual string GetSomething() {...} 
} 

public interface IMixin
{
  void ResetCache();
}

[Extends (typeof (Target))]
public class Mixin: Mixin<Target>, IMixin 
{
  private string _cache = null;

  [OverrideTarget] public string GetSomething ()
  {
    if (_cache == null)
      _cache = Base.GetSomething();
    return _cache;
  }  

  void ResetCache()
  {
    _cache = null;
  }
}

[CompleteInterface (typeof (Target))]
public interface ICompleteTarget : ITarget, IMixin {} 

ICompleteTarget t = ObjectFactory.NewObject<ICompleteTarget>().With("stringArg");

This simply creates a mixin that caches the result of GetSomething(). This also points out the difference between mixins and generic AOP mechanisms: An AOP system would allow you to create code that caches every method/property (or lets you choose them based on attributes or regular expressions). Mixins are strictly non-generic. They work on known interfaces and methods, which means that we don’t get the complexity overkill of AOP (but also not the full power of AOP).

(That said, there are ways to use the mixin infrastructure for more generic behavior, but that’s a different story.)

Here’s a short list of features:

  • Create full-featured mixins (implement new interfaces, override virtual methods/properties/events, call “base”-methods, keep state) using the most simple syntax we could possibly come up with.
  • Include one or more mixins from a target type (similar to multiple inheritance) and even override methods of the mixin OR
  • define a mixin for one or more existing types, and just have it magically applied to that type (as long as instances are created via a factory method). You can even create a mixin in a new assembly, copy it into an app’s bin directory and have it picked up automatically, so that existing types just magically “change” (we’re using this for product extensibility and product line development)
  • This even works if you apply multiple mixins to a single target type. If several mixins override the same method, they are automatically ordered based on their dependencies.
  • Automatically implement “complete interfaces”, i.e. interfaces that include members of both target type and mixins, so you don’t have to cast that much.
  • For those of us who use WebForms, which “new” up objects all the time without any chance to use a factory method, there is a special mechanism that replaces the static types in the markup with generated types at runtime.
  • You can apply mixins to any public, non-sealed type, and you may use any type as a mixin. For advanced features like overriding however, the type that does the overriding of course has to be mixin-aware. Also, mixins are easier to use if both target types and mixin types expose their features via interfaces, but this is not a requirement.
  • You can modify the static assignment of mixins to types at runtime.
  • Types with mixins are fully serializable (assuming that all underlying types are).
  • There’s a load of advanced features, like copying mixin attributes to target types, reflecting on mixin types, customizing ordering via dependencies, manually instantiating mixins (behind the scenes, it’s just composition after all), scoped configurations, imperative configuration, parallel class hierarchies between target and mixin types, and type deduction for generic mixin types, to name just a few. For those who really know what they are doing 😉

This sounds more complicated than it is, in most cases you just write a mixin class, optionally apply a few attributes for overriding, and then specify which mixins you want to use for which target type. We’ve used this library internally now for a few months, and feedback has been very good so far. It turned out that, while started primarily with a focus on product line development, mixins are a very useful general-purpose design tool.

Finally, a word about the preview version you can download from here: It is not yet open source, basically because we didn’t get around to finish all the work we need to do first (license headers etc). Since mixins are only a part of what re:motion is providing, this is quite a bit of work. The other thing is that we’re using Castle’s DynamicProxy library. That’s because Reflection.Emit is a pain to work with directly (mostly because of the less-than-helpful error handling). So we’re using DynamicProxy’s type emitters, but we’re not using its proxy mechanisms. So don’t jump to any conclusions about our implementation just from the fact that we’re referencing it.

OK, that’s it for today, download and have fun!

– Stefan

Written by Stefan Wenig

February 20th, 2008 at 2:54 am

Posted in mixins

Leave a Reply