Wednesday, June 09, 2010

Using the dynamic keyword to select behavior

I won't get into explaining in detail what the dynamic keyword does in .Net 4.0, enough to say that it is enabled by the DLR (Dynamic Language Runtime) and it allows an object to have a type determined at runtime, not at compile time. I will use this feature to select the appropriate method for a specific type.

I've long had this problem with the object oriented principles that stated that methods with different signatures should be chosen based on the type of their parameters, but if the type of the parameter was unknown at compile time (let's say it was boxed in an object type) the method executed was always the one with the object parameter:

void DoSomething(object o) {
Console.WriteLine("I'm an object");
}

void DoSomething(int o) {
Console.WriteLine("I'm an int");
}

void Test() {
int i=1;
object o=i;
DoSomething(i);
DoSomething(o);
}

The result of this would be "I'm an int" followed by "I'm an object".

Solutions for this range from having a type casting cascade (because the switch statement doesn't work with Type) or using a Dictionary<Type,Action> or even using reflection to get the method with a specific signature and execute it.

A typical OOP solution that is correct, but really cumbersome to use is the double dispatch pattern. You can read an interesting article about it here.

The worst thing about this is that o.GetType() is System.Int32. It's like it's mocking us (and not in a unit testing way either).

Here comes dynamic:

void DoSomething(object o) {
Console.WriteLine("I'm an object");
}

void DoSomething(int o) {
Console.WriteLine("I'm an int");
}

void Test() {
int i=1;
object o=i;
dynamic d=o;
DoSomething(i);
DoSomething(o);
DoSomething(d);
}

This will have the same result as before followed by "I'm an int"! Pay attention to the fact that I did not set the value of d to the int, but to the object! What is ever cooler is that one can use only the methods that make sense, without the need of a general method that received a parameter of type object (unless, of course, you want to catch it and throw some meaningful error). No more casting insanity!

I use this technique to get an object that inherits from a base class, without knowing what the object is, then passing it to private methods that have the same name but different parameter types. All I have to do is cast my object to dynamic and pass it to the private method and the DLR does the rest for me.

I have not yet tested the performance aspect of this, but, considering that the DLR is the base for all dynamic languages in .Net like Ruby and Python, I bet it is faster than dictionaries with Actions in them.

So, to recap, if you ever want that a boxed object behave differently based on its true type, use myMethod((dynamic)obj) rather than myMethod(obj) and you are set.

Update: I have implemented this pattern in an application I am working on and I am very satisfied with it. I've created a separate assembly that adds the DynamicPatternAttribute and DynamicPatternIgnoreAttribute classes, which help decorate the methods I am using and also a PatternChecker class that can be used to check that there is a method implementation for each type inheriting from a specific base type. Here are some details on how it works.

First of all, we must define the purpose of such a pattern. As I said above, one can use it to specify behavior based on specific types that inherit from a base type. This can be desirable when the types in question cannot be changed to add new behavior. Even if they can be changed, it may not be desired to add a reference from the project containing our classes to the project containing the behavior. It is almost like defining static extension methods.

Then there are the elements:
  • The base class from which all classes that determine behavior inherit (object if nothing specific)
  • The routing method that receives at least a base class parameter
  • The behavior methods that have as a parameter the subclasses of the base type
  • The pattern implementation checker class


So far I've used it in the following way:
  • The new behavior is encapsulated in methods in a static class
  • The routing method receives as the first parameter the base type for the classes that should determine behavior
  • The only code in the routing method is calling the private behavior method(s) using the same parameters as itself, except the first which is cast to dynamic
  • The behavior methods usually are private methods having the same name as the routing methods, but ending in "handle"
  • The routing method is decorated with [DynamicPattern("nameOfTheBehaviorMethods")]
  • The routing method is decorated with [DynamicPatternIgnore(typeof(subClassToIgnore))] which tells the checker which classes do not need behavior implementations
  • The static class containing the pattern has a static constructor that calls a method to check the implementation of the pattern
  • The checker method is decorated with [Conditional("DEBUG")] so that it doesn't hinder the functionality of the program with slow reflection checks
  • The checker method calls PatternChecker.CheckImplementation(typeof(staticClass)) or PatternChecker.CheckImplementation(typeof(class).Assembly)


The PatternChecker class only checks if there is a method with the name specified in the DynamicPattern contructor for each of the subclasses of the base type of the first parameter in the routing method.

I hope you like this pattern. I certainly do. I leave you with an actual implementation example:

public static class RequestHandler
{

static RequestHandler()
{
checkDynamicPattern();
}

[Conditional("DEBUG")]
private static void checkDynamicPattern()
{
PatternChecker.CheckImplementation(typeof(RequestHandler));
}

[DynamicPattern("getObjectsHandle")]
[DynamicPatternIgnore(typeof(BaseDeleteRequest))]
[DynamicPatternIgnore(typeof(DeleteUsersRequest))]
[DynamicPatternIgnore(typeof(DeleteCategoriesRequest))]
[DynamicPatternIgnore(typeof(DeleteDataRequest))]
[DynamicPatternIgnore(typeof(DeleteApplicationsRequest))]
[DynamicPatternIgnore(typeof(GetEntityRequest))]
[DynamicPatternIgnore(typeof(BaseObjectActionRequest))]
[DynamicPatternIgnore(typeof(GetEntitiesRequest))]
[DynamicPatternIgnore(typeof(GetEntityByIdRequest))]
[DynamicPatternIgnore(typeof(BatchOperationRequest))]
public static BaseEntitiesResponse GetObjects(BaseRequest request, Coordinator coordinator)
{
return getObjectsHandle((dynamic)request, coordinator);
}

private static BaseEntitiesResponse getObjectsHandle(BaseRequest request, Coordinator coordinator)
{
throw new ArgumentException("Cannot find a suitable getObjects method for type of request " +
request.GetType());
}

private static BaseEntitiesResponse getObjectsHandle(GetApplicationRequest request,
Coordinator coordinator)
{
DataObject entity = coordinator.ApplicationManager.GetObject(request.Id,
request.IncludeOptions);
return getEntitiesResponse(entity);
}



Update: There is an wonderful unintended side-effect of the dynamic pattern when casting to generic types. Imagine you have a generic interface like ICustom<T> and you want to use the standard model of checking the type and selecting behaviour. You can't do it with as! There is no valid method of doing
var custom=obj as ICustom<T>;
so you are forced to use GetType() and then some weird methods that interogate the Type object. You can do it with the dynamic pattern.



checkIfCustom(obj);

private void checkIfCustom(object obj) {
dynamicCheckIfCustom((dynamic)obj);
}

private void dynamicCheckIfCustom(object obj) {
//do nothing
}

private void dynamicCheckIfCustom<T>(ICustom<T> iCustom) {
doSomethingWith(iCustom);
}


This thing works! If anything than an ICustom<T> is given, nothing happends. If it is the correct type, then doSomething is executed with it. Pretty neat, huh?

2 comments:

irium said...

Thank you! It's an interesting and useful technique, nice trick))

Siderite said...

Hey, thank you! I have been using it a lot since I have written the post and I trully feel that it is helping rather than going against OOP principles.