Showing posts with label PDC. Show all posts
Showing posts with label PDC. Show all posts

Thursday, October 30, 2008

Dynamic Dispatch in C# 4.0

So C# 4.0 is finally with us (in CTP form anyway). I've just been watching Ander's PDC presentation, The Future of C#. The main focus is providing interop with dynamic languages and COM, so in order to do that they've added some dynamic goodness in C# itself. There's a new static type called dynamic :) Yes, it's the number one joke at PDC it seems. The dynamic keyword allows us to say to the compiler, "don't worry what I'm doing with this type, we're going to dispatch it at runtime".

Take a look at this code:

using System;
using Microsoft.CSharp.RuntimeBinder;
using System.Scripting.Actions;
using System.Linq.Expressions;
namespace ConsoleApplication1
{
    public class Program
    {
        static void Main(string[] args)
        {
            DoSomethingDynamic(7);
            DoSomethingDynamic(new Actor());
            DoSomethingDynamic(new DynamicThing());
            Console.ReadLine();
        }
        static void DoSomethingDynamic(dynamic thing)
        {
            try
            {
                thing.Act();
            }
            catch (RuntimeBinderException)
            {
                Console.WriteLine("thing does not implement Act");
            }
        }
    }
    public class Actor
    {
        public void Act()
        {
            Console.WriteLine("Actor.Act() was called");
        }
    }
    public class DynamicThing : IDynamicObject
    {
        public MetaObject GetMetaObject(System.Linq.Expressions.Expression parameter)
        {
            return new CustomMetaObject(parameter);
        }
    }
    public class CustomMetaObject : MetaObject
    {
        public CustomMetaObject(Expression parameter) : base(parameter, Restrictions.Empty){ }
        public override MetaObject Call(CallAction action, MetaObject[] args)
        {
            Console.WriteLine("A method named: '{0}' was called", action.Name);
            return this;
        }
    }
}

OK, so we've got a little console application. I've defined a method, DoSomethingDynamic, which has a parameter, 'thing', of type dynamic. We call the Act() method of thing. This is duck typing. The compiler can't check that thing has an Act method until runtime, so we're going to wrap it in a try-catch block just in case it doesn't. A side effect of duck typing is that there's no intellisense for the thing variable, we can write whatever we like against it and it will compile. Any of these would compile: thing.Foo(), thing + 56, thing.X = "hello", var y = thing[12].

Next, in the Main method, we call DoSomethingDynamic a few times, passing in different kinds of arguments. First we pass in the literal 7. Int32 doesn't have an Act method so a RuntimeBinderException is thrown. Next we pass an instance of a normal C# class, Actor. Actor has an Act method so Act is called normally as expected.The last invocation of DoSomethingDynamic shows off how you can do dynamic dispatch in C# 4.0. We define a new class called DynamicThing and have it inherit IDynamicObject. IDynamicObject has a single method you must implement: GetMetaObject. GetMetaObject returns a MetaObject and all you have to do is implement a CustomMetaObject that knows what to do with any method (or parameter, or indexer etc) invocation. Our CustomMetaObject overrides Call and simply writes the name of the method to the console. Chris Burrows from the C# compiler team has a series of three blog posts showing off these techniques here, here and here. Anders' PDC presentation, The Future of C# is here. C# is primarily a statically typed language and Anders obviously still believes that static typing is a better paradigm for large scale software. He sees the dynamic features as a way of adding capabilities to C# that have previously been the prerogative of VB and dynamic languages. He's especially contrite about the failure of C# to interoperate with COM efficiently in the past. However there are going to be lots of cases when using dynamic will be a short cut to features that are hard to implement statically. I can see the C# forums humming with complaints that intellisense doesn't work anymore, or hard to diagnose runtime errors as a result of over zealous dynamism.

The last ten minutes of the talk, when he showed us some of the post 4.0 features, was very cool. They are rewriting the C# compiler in C#. This means that the compiler API will be just another library in the framework. Applications will be able to call compiler services at runtime giving us lots of Ruby style meta-programming goodness. Tools will be able to read the C# AST, giving us incredible power for refactoring or post compilation style tweeks.

Jim Hugunin has a related presentation, Dynamic Languages in Microsoft .NET that goes deeper into the dynamic features that Anders talks about. Also well worth watching.