Fabian's Mix

Mixins, .NET, and more

Declare mixins, not war!

with 3 comments

This is the fourth in a series posts. The previous items are:

Last time, I briefly mentioned configuration as a feature of the re-motion mixin implementation. In the context of mixins, the term “configuration” refers to what mixins are mixed into what target classes, and with what properties the mixing is performed.

To be honest, the notion of configuration is more a prerequisite than a feature – without the ability of assigning mixins to target classes, a mixin implementation would be rather stupid. Or… not a mixin implementation at all, actually. What is a feature, however, is how many ways of configuration we allow.

I quickly repeat them from my last post:

  • A class can declaratively choose to be extended by one or more mixins.
  • A mixin can declaratively choose to extend one or more classes.
  • An application can declaratively choose to combine mixins and classes.
  • A programmer can – at run-time – choose to combine mixins and classes.
  • (Any person can – at deployment time – choose to combine mixins and classes.)
    –> planned, but not implemented yet

Today, I’ll write about the first three topics – the declarative configuration possibilities.

A class can choose its mixins

When you write a new class, you can explicitly pull in a number of mixins into that class. This feature is similar to inheritance (where you explicitly derive from a base class), and it enables scenario (1) from my post on usage scenarios:  having a class reuse an implementation supplied by a mixin.

Let’s look at an example:

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

That’s quite self-explaining, I think – MyClass has chosen to use (ie. include) the reusable code provided by MyMixin.

Now, what would you use that for, and what additional properties can you specify?

You would choose this form of configuration when you have a mixin providing a feature that you want your class to expose. The mixin’s implementation actually becomes part of the class’s implementation. Think of deriving from a base class, or of aggregating and delegating to another component. For example, you could want to make your class cloneable by reusing a mixin:

[Uses (typeof (CloneabilityMixin))]
public class MyCloneableClass
{
}

And the test:

[Test]

public void MyCloneableClass_IsICloneable ()

{

  var instance =
    ObjectFactory.Create<MyCloneableClass> (ParamList.Empty);

  Assert.That (instance, Is.InstanceOfType (typeof (ICloneable)));

}

(We will look at the actual implementation of the CloneabilityMixin at a later time.)

That way, the class will always support cloning, the implementation supplied by the mixin has become a part of MyClass’s implementation.

The UsesAttribute supports the following optional parameters:

  • IntroducedMemberVisibility: As you know from my feature post, mixins can add interface implementations to the mixed object. By default, the members added by such an interface implementation are explicit implementations, ie. private. If you need those members to be made public, which might make sense in some reflection scenarios, you can do so by specifying MemberVisibility.Public to the attribute.
  • AdditionalDependencies: I will write about dependencies in another post, but for now it should be enough to say that mixins can have dependencies on other mixins, either directly or indirectly. Dependencies influence the base call order when more than one mixin overrides the same members, and they also define what a mixin can rely on when it accesses the mixed object. Explicit dependencies can be defined via this parameter by passing an array of mixin types to the attribute.
  • SuppressedMixins: By default, every target class inherits the mixins configured for its base classes. Sometimes, however, a class might want to replace an inherited mixin with another one – so the new mixin declaration needs to suppress a previous one. Which is what this attribute parameter is for.

Uses is nice, but you could argue that you could replace it simply by having your class hold an instance of the mixin and delegate to it, or even by deriving your class from the mixin. In reality, that “simply” will usually not be so simple at all, because delegation quickly becomes cumbersome and lengthy, and base classes are scarce (only one per class) in the .NET world. Still, let’s look at something you can’t do that easily with manual delegation or inheritance.

A mixin can choose its target classes

Consider scenario (2) from my usage scenario post: you have a finished class model, but need to adapt it. How do you do that?

That’s easy – just create a mixin specifically for those target classes you need to adapt:

[Extends (typeof (MyClass))]

public class MyMixin

{

}

Now, while this might seem to be only an inversion of the example given above, semantically it’s much more: It allows a mixin to extend a class from the outside. So, if we follow the base class analogy, this would be like specifying the base of a class from the outside. Try this in C# 🙂

To give a more realistic example, consider a scenario where you have a pre-implemented file management domain, and you have a client requirement to number files in a specific format. While you could simply derive from the pre-implemented File class to add that information (and hope your domain uses inversion of control to instantiate its File objects…), consider that your domain might already contain CarFile, PersonFile, and other subclasses of File. That would quickly result in a subclassing orgy, and all of the subclasses would hold the same delegation code!

So, how to do this, then? Remember, classes automatically inherit mixins from their base classes, so if we implement mixin for this, it should be much more efficient. And it is:

[Extends (typeof (File))]

public class NumberedFileMixin : INumberedFile

{

  private readonly string _id = Guid.NewGuid ().ToString();

 

  public string GetFileNumber ()

  {

    return _id;

  }

}

And the test for this:

[Test]

public void File_IsNumbered ()

{

  var numberedFile = (INumberedFile)
    ObjectFactory.Create<File> (ParamList.Empty);

  var numberedCarFile = (INumberedFile)
    ObjectFactory.Create<CarFile> (ParamList.Empty);

  var numberedPersonFile = (INumberedFile)

    ObjectFactory.Create<PersonFile> (ParamList.Empty);

 

  Assert.That (numberedFile.GetFileNumber (),

    Text.Matches (“……..-….-….-….-…………”));

  Assert.That (numberedCarFile.GetFileNumber (),

    Text.Matches (“……..-….-….-….-…………”));

  Assert.That (numberedPersonFile.GetFileNumber (),

    Text.Matches (“……..-….-….-….-…………”));

}

(Note that I needed to cast to INumberedFile because the C# compiler can’t know that File now implements INumberedFile via a mixin. There are ways to avoid the cast, but that will go into a separate blog post…)

The ExtendsAttribute supports the same optional arguments as the UsesAttribute does (IntroducedMemberVisibility, AdditionalDependencies, and SuppressedMixins), plus one:

  • MixinTypeArguments: Consider the case where you have a generic mixin (if you can’t imagine this, take a look at Stefan’s blog post about mixins in domain design). re-motion’s mixin implementation has an algorithm that tries to supply the type arguments automatically when the mixin is instantiated, but sometimes, the algorithm won’t be able to figure out what you want. In these cases, you’ll need to specify the type arguments by hand using this attribute. (Prize question: Why doesn’t the UsesAttribute need this parameter?)

So, you use the ExtendsAttribute when you write a mixin for specific target classes, and you use the UsesAttribute when you write a class using a specific mixin. Can there be anything else?

Well, what if you want both classes and mixins to be fully oblivious of each other?

An application can combine mixins and classes

Say, for example, you reference a DLL with a finished class model, and you also have a catalog of adaptation mixins for different client scenarios. Now, in your application, you just need to combine the relevant mixins with the respective domain classes. re-motion also supports this:

[assembly: Mix (typeof (MyClass), typeof (MyMixin))]

In this case, the programmer has chosen (via an assembly-level attribute) that instances of MyClass should be mixed with MyMixin in the context of the application. Let’s apply the same to the file numbering sample from above:

[assembly: Mix (typeof (File), typeof (IdentifiedObjectMixin))]

And the test:

[Test]

public void File_HasID ()

{

  var numberedFile = (IIdentifiedObject)

    ObjectFactory.Create<File> (ParamList.Empty);

  var numberedCarFile = (IIdentifiedObject)

    ObjectFactory.Create<CarFile> (ParamList.Empty);

  var numberedPersonFile = (IIdentifiedObject)

    ObjectFactory.Create<PersonFile> (ParamList.Empty);

 

  Assert.That (numberedFile.GetObjectID(),

    Text.Matches (“……..-….-….-….-…………”));

  Assert.That (numberedCarFile.GetObjectID(),

    Text.Matches (“……..-….-….-….-…………”));

  Assert.That (numberedPersonFile.GetObjectID(),

    Text.Matches (“……..-….-….-….-…………”));

}

Note that I’ve renamed the mixin and the interface to denote a more general mixin implementation. This is exactly the point: the MixAttribute allows you to combine completely general (or “oblivious”) classes and mixins.

The attribute accepts the same properties as the UsesAttribute (IntroducedMemberVisibility, AdditionalDependencies, and SuppressedMixins), plus one:

  • MixinKind: Now, what’s that? This parameter takes an Enum value that allows you to choose: do you want to regard the mixin to be extending the target class, or the class to be using the mixin? That’s not really important from the point of view of the mixin engine, but there might be user code that needs to differentiate between these two scenarios. And for such user code, you can specify the relationship. (The default is MixinKind.Extending, by the way.)

So, to wrap it up, re-motion offers three forms of attribute-based declarative mixin configuration:

  • The UsesAttribute, by which a class can include mixins, which is similar to inheritance,
  • the ExtendsAttribute, by which a mixin can extend a class, which is good to adapt classes from the outside, and
  • the MixAttribute, by which an application programmer can combine any class with any mixin.

Use them wisely, and you shall prevail.

Next time: Probably something short about mixins and inheritance.

Edit: You can find the code for this blog entry here:
<https://svn.re-motion.org/svn/Remotion/trunk/Remotion/Core/Mixins.Samples/Tutorial/T01_Configuration/>.
The tests are here:
<https://svn.re-motion.org/svn/Remotion/trunk/Remotion/Core/Mixins.Samples/UnitTests/Tutorial/T01_Configuration/>.

Written by Fabian

February 2nd, 2009 at 10:39 am

Posted in mixins

3 Responses to 'Declare mixins, not war!'

Subscribe to comments with RSS or TrackBack to 'Declare mixins, not war!'.

  1. Fabian Schmied

    2 Feb 09 at 16:26

  2. Hi Fabian,

    you might want to update your blog post at http://www.re-motion.org/…/the-art-of-mixing.aspx with a link to this post, because as of now it has been quite cumbersome to find more detailed info on how to use and implement mixins.

    This post has been quite helpful, though 🙂

    Also, a navigation item linking to an overview of all mixins post, would be handy!

    Cheers, Oliver

    Oliver Friedrich

    27 Dec 10 at 22:59

  3. Hi Oliver,

    Thanks for the comment – you can find all of my mixin-related posts by browsing the archive by category. Here’s the direct link: http://www.re-motion.org/blogs/mix/category/11.aspx. I’ve updated the Team Blog post with that link as well.

    If you have any specific questions about re-motion mixins (how to use them, why something doesn’t work as you’d expect, etc.), please post them to our Google Group: http://groups.google.com/group/re-motion-users.

    Fabian

    fabian

    3 Jan 11 at 08:35

Leave a Reply