Mixin in C# 3






3.34/5 (13 votes)
How to add mixin to a class in C# 3
Introduction
Note: It's probably pretty early to start talking about patterns for C# 3, but the thought popped in my mind and wouldn't go away.
Mixin: In computer science, a mixin is a group of functions which can be mixed into a class and become methods. They allow certain classes to take on certain functionality, in an object-oriented programming including in languages that do not support multiple inheritance, just as if the class were a cooking dish and a mixin was a specific ingredient.Ruby on Rails recently got a act_as_taggable mixin, which basically allows you to just slap a single line of code on a class and get tagging support. I'm going to show the C# 3 interface for a similar implementation. I don't care about the implementation, so we'll just assume that this is a given. I want to be able to tag any database object with as few lines of code as possible and just have it work like magic, the ideal is Ruby's single line of code. I'm going to show the ideal, the interface & client code and then talk about how this is possible.
The Code
Let's see what we would like to write:
//Creating taggable mixin
public mixin Taggable<T>
{
public void TagWith(params string tags) { .. }
public static T TaggedWith(params string tags, FindWith with) { .. }
}
public enum FindWith
{
AnyOfTheTags,
AllTheTags
}
//Adding tagging to a class
public class Photo : Taggable
{
...
}
//client code:
// create photo and adding tags
Photo photo = ... ;
photo = Photo.TaggedWith("flower","sun","yellow", "mayhem");
//Loading with tags
Photo photo = Photo.TaggedWith("flower", FindWith.AnyOfTheTags);
This is what we would like to have, but right now and in the future we are not likely to get it. We can get something very close. Here is what we would need to write:
//creating taggable mixin
namespace Tagging
{
public static class Taggable
{
public static void TagWith(this ITaggable<T> tagged, params string tags) { .. }
public static IList<T> TaggedWith<T>(params string tags, FindWith with)
where T : ITaggable<T> { .. }
public interface Mixin<T> where T : ActiveRecordBase, Mixin<T> { }
}
public enum FindWith
{
AnyOfTheTags,
AllTheTags
}
}
//Adding tagging to a class
public class Photo : ActiveRecordBase, Taggable.Mixin<Photo>
{
...
}
//client code
using Tagging;//create photo and adding tags
Photo photo = ... ;
photo.TagWith("sun","rain","colors");
//load photo with tags
IList<Photo> photoWithFlowers =
Taggable.TaggedWith<Photo>("chaos", FindWith.AnyOfTheTags);
So, what do we have here? We have a static
class with extension methods that refer to the Taggable.Mixin<T>
interface. The Taggable.Mixin<T>
interface requires that the implementing class will inherit from ActiveRecordBase and implement ITaggable*
, this is so the Taggable
class will have a way to work with the database, (that is an implementation detail, it can certainly be done in other ways).
Then we have the Taggable
class, which has an extension method to add tags to an object, and a static
method (not an extension one), which takes a Taggable.Mixin
type and returns a list of the tagged instances of it. Check out the bolded lines, those are what you've to do in order to get the taggable support for an object. Add a declaration to Taggable.Mixin
, and your object is set. Then in the client code, just import the Tagging
namespace, and you can use it as if it was part of the object.
I think that this is a really nice way to add functionality to objects in a non intrusive way. The client code can actually choose whatever it wants to be exposed to the tagging support or not, and all the class has to do is to declare its intention to accept the mixin.
As I said, it's pretty premature to start thinking about patterns for C# 3 (C# 2 is not yet released, after all), but I'm willing to bet quite a sum that this will be the way to create mixins is the .NET Framework. This is just one of the cool things that you can do with the things that C# 3 will give you. I expect a lot more goodies along the way. The new features are useful for so much more beyond LINQ.
One thing to be considered, it's pretty early to say anything, but I can certainly see libraries such as the Boost providing tremendous value for developers in the C# 3 world.
Implementing Taggable.Mixin
Since Taggable.Mixin
is an empty interface, the constraints here are just a way to say that any Taggable.Mixin
must inherit from ActiveRecordBase
. It's a nice way to declare things, since now we can say: ITaggable<Photo>
is ActiveRecordBase
, and it's always true
.
For mixin today you can use Castle.DynamicProxy.
History
- 19th September, 2005: Initial post