Bringing The Heat With Dynamic

Writing

For a little while now I have been feeling a bit restless when it comes to programming on the .net platform. I love C#, it is my current language of choice, but I get so jealous when I talk to the Java guys at work and see all of the freaking awesome tools that they have for free on their platform. Since I use the NUnit, NCover, NHibernate, NAnt stack when doing most .NET development, sometimes I feel like we are just a bunch of copycats. I want something neat and unique! (And to be fair, there actually is quite a lot of innovation going on in the .NET space!)

Well, tonight I went to see my good friend Kevin Hazzard talk about DLR/C# interop performance in VS2010 (the talk was great, go check it out) and he gave me a great “smack to the face” reminder of one huge thing that we have coming in C# 4/.NET 4.0 that is quite unique. And that is the dynamic keyword. In order to full appreciate its value, you have to see it used in terms of its interop with dynamic languages.

In its most basic form though, it just allows you to perform late binding:

class SomeClass 
{ 

}

class Program 
{ 
    static void Main(string[] args) 
    { 
        dynamic someClass = new SomeClass(); 
        someClass.Hello(); 
    } 
}

As you can see, there are no methods on “SomeClass”, but the code below compiles. It will fail at runtime, but it compiles because the binding on the dynamic object is done at runtime. Pretty cool, there is definitely a few places where you could do some neat stuff with this.

The first thing we can do is to implement a dynamic object (descends from DynamicObject). What this allows us to do is to implement an object which intercepts dynamic operations made on it to perform actions. So for instance, we can create a class that looks like this:

class Person : DynamicObject 
{ 
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 
    { 
        result = binder.Name; 
        return true; 
    } 
}

Here we are overriding the method which is called when a member is invoked. Then we take the InvokeMethodBinder that gets passed into the method and set the result to the name of the method that was called. Then all we have to do is return true to say that we handled the call properly. Now we can consume this class like this:

class Program 
{ 
    static void Main(string[] args) 
    { 
        dynamic person = new Person(); 
        string methodName = person.ReturnThisMethodName(); 
        Console.WriteLine(methodName); 
    } 
}

Just as we expect, the call to “ReturnThisMethodName” returns the same name as a string. Here is the output:

 image

Pretty crazy stuff. There are quite a few methods we can override to call all of the different operations that we need in order to interact with an object. More importantly though, when we get the information passed to a dynamic object, we don’t necessarily need to turn around and directly execute some code in response to the information we received, we could actually pass this information off to some other runtime and translate it into some other format for consumption.

So if you had something like…. well… an object  for interacting with a dynamic language. But first, let’s declare a simple Ruby class:

class Person    
    def set_first_name(first_name) 
        @first_name = first_name 
    end 
    def set_last_name(last_name) 
        @last_name = last_name 
    end 
    def say_something(value) 
        puts value 
    end 
    def full_name 
        @first_name + " " + @last_name 
    end 
end

Looks good, although I am using setter methods for a particular reason which we will see in a second. A very simple Ruby class with two setter methods for first name and last name as well as a method that writes a value to the console and one which returns the first and last names concatenated together. In C# 3.0 in order to create and interact with this Ruby object we would need to do this:

var runtime = IronRuby.Ruby.CreateRuntime(); 
ScriptScope scope = runtime.ExecuteFile("person.rb"); 
var operations = scope.Engine.CreateOperations(); 

Object person = scope.Engine.Execute("Person.new"); 
operations.InvokeMember(person, "set_first_name", "Justin"); 
operations.InvokeMember(person, "set_last_name", "Etheredge"); 
Console.WriteLine(operations.InvokeMember(person, "full_name")); 
operations.InvokeMember(person, "say_something", "hello");

Ugh. That is just a bit hideous. We are loading up the file, then calling the constructor, then setting both properties. Next we call “InvokeMember” and get the full name and write that to the console. Next we pass “hello” to the “say_something” method and it writes it out to the console. This all works as expected, but the code leaves a bit to be desired.

But hey! That little dynamic object thingy we looked at earlier would be perfect for this! Right? Of course! We could just turn those methods that get called into calls on the IronRuby operations. And thankfully, Microsoft has already written the implementation for me so I don’t need to worry about it! All I have to do is just assign the result of the Execute method to a variable of type dynamic:

var runtime = IronRuby.Ruby.CreateRuntime(); 
ScriptScope scope = runtime.ExecuteFile("person.rb"); 
dynamic person = scope.Engine.Execute("Person.new"); 

Awesome, now we can call methods on it just like it is a native C# object:

person.set_first_name("Justin"); 
person.set_last_name("Etheredge"); 

Console.WriteLine(person.full_name()); 
person.say_something("hello");

You’ll notice though that we are calling everything as methods. This is because when you use accessors in Ruby they generate methods to get and set. The one to get the value looks like “first_name” and the one which sets the value looks like “first_name=”. The problem is that C# doesn’t allow for methods to have an equal sign in them. This creates a bit of a problem, but I’m sure that they will work around it in some way. In fact, they may have already worked around it in some way that I am unaware of.

As you can see, this provides for some really powerful capabilities and excellent dynamic interop. If you want to check all of this coolness out for yourself, go check out the .NET 4.0 beta 1 builds of IronRuby and grab the VS2010 Beta 1.

Loved the article? Hated it? Didn’t even read it?

We’d love to hear from you.

Reach Out

Comments (5)

  1. Frankly: while I can see some use of that in some scenarios, it overall makes me shudder. This is nothing than a fallback into long overcome, really bad VB6 times.
    I already can see the miriads of software faults and maintenance nightmares that result from this language feature…

  2. @Thomas While I can understand the concern, I think that the potential in certain areas can outweigh the downsides. Millions of developers write in dynamic languages every day and the sky is not falling. Creating safe and bug-free dynamic code may be more difficult, but it is most certainly not impossible. Having small islands of dynamicness gives us the type safety that most of us want 99% of the time, while still giving us the dynamic abilities that we use 1% of the time. Besides, it isn’t giving us anything that we don’t already do with reflection, it is just making it easier, faster, and less error prone.

  3. Sure, the sky will not fall and it can be very powerful when used wisely. But this is only one side of the story. The other side is that it fosters bad coding practices and will be used in ‘creative’ ways it was not intended for. This is why I think the downsides will by far outweigh the advantages in the long run.

  4. @Thomas But if we dropped a language or library feature every time people thought it would be abused, then I don’t think that our languages would do anything. There are a million features in C# which can be abused to no end. Doesn’t mean the features shouldn’t be there though.

  5. Six years later and I have only just recently discovered the joys and (to me) novel approach of incorporating dynamic typing into my C#. A few months ago at work I implemented a pleasant but slightly inconvenient solution involving several large classes generated with Code Dom. I can replace their entire functionality with a single class inheriting from DynamicObject.

    I would contend that the code itself never fosters bad coding practices (at least not in any widely used languages, I’m sure one could invent a counterexample). We foster bad coding practices ourselves as developers because for one reason or another we didn’t know what we were doing. Ignoring the benefits of dynamic typing makes just as much sense as ignoring the benefits of static typing.

Leave a comment

Leave a Reply

Your email address will not be published. Required fields are marked *

More Insights

View All