Redlining C#’s Dynamic Features

In my last post I discussed using the new "dynamic" keyword for passing method parameters. I've received (as expected) some great and various responses. Do strong types and intellisense make for a better API? You tell me! In this post I'll put the pedal to my dynamic mettle and see just how far I can push C# before it explodes...


Dynamic Is More Than a Keyword

I got the idea for this post last week – and I called Jon Galloway. It’s what I do when an idea hits – Jon, it turns out, is the only one who has the patience to listen.

  • Me: “Dude – what if every property in your app was dynamic? What if every method returned dynamic… do you know what you’d have?!?!?!”
  • Jon: “Uhhhh”
  • Me: “Something as close to a true dynamic experience as you can possibly get!”
  • Jon: “Why would you ever want to do something like that?”
  • Me: “I don’t really know – but it would be fun to find out…”

Before I go any further: the point of this post isn’t to convince you of anything (where have I read that before?) – it’s to explore a new language feature completely and, hopefully, have a good discussion on it. If you are feeling a bit of a gag reflex – I think It’s important to know why. What is it that is causing you to dislike what you’re about to see? C# is going more and more dynamic – time and feature set have proven that. Maybe it’s time to bend your thinking? Or maybe it’s not…

The conversation with Jon was great – Jon’s always receptive. What it came down to was that I wanted to see just how far I could push the “dynamic envelope” with C#. I’m pleased to say the answer is “rather far” – not without a bit of a headache, but it’s actually possible to approximate some of of the interesting things you can do with Ruby.

To understand this (and the code you’re about to see), you have to shift your brain into Dynamic Mode. It’s more than aesthetic, more than shortcuts and sugary syntax:

You have to focus on what an object can do, not what it is.

Everything Is a Nail?

Let’s start with some code. In Ruby, you can do this and it works fine:

class Address
  attr_accessor :number, :street, :city, :state, :country
end

class Person
  attr_accessor :name, :address
end

p1 = Person.new
p1.name = "Mary"
p1.address = "Number 17, Cherry Tree Lane"

p2 = Person.new
p2.name = "Burt"

p2.address = Address.new()
p2.address.number = 17
p2.address.street = "Cherry Tree Lane"
p2.address.city = "London"

Ruby let’s you declare a property and assign it what you want, when you want, how you want. It’s not important what the object is – it’s more important that you can get what you want out of it. In this example – let’s say all we care about it using this address to show on screen. Let’s send a message to Address and ask it for its string representation:

puts p1.address.to_s
puts p2.address.to_s

The response would be:

Number 17, Cherry Tree Lane # <-- p1
#<Address:0x1001551e8> # <-- p2

That doesn't help too much - so we'll need to tweak Address a bit:

def to_s
  "Number #{number} #{street}\n#{city}"
end

Now the output is equal:

Number 17, Cherry Tree Lane  # <-- p1
17 Cherry Tree Lane  # <-- p2
London

So what did we gain here? The quick answer is we went from simple (a string representation of an Address) to complex without breaking our code. It's reasonable to assume that at some point in an app's lifecycle you might want to imbue a Person's Address with other capabilities - at the onset however those needs might not exist, so a string is just fine.

Using a static language approach, however, usually pushes you to try and think ahead a bit - you don't want to break your app or your model and refactoring can be a pain in the ass. This leads to (guess what) over-engineering an application from the start. Something that many (not all, of course) .NET apps suffer from.

I'd like to point out that, ideally, you wouldn't want to use a string and an Address at the same time like I did here - this is not my point. The point was, specifically, that I didn't need to change Person at all in order to get a formatted address output. I'll talk more about this below...

Using C# To Do The Same Thing

We can do precisely the same thing with C# 4.0 - believe it or not:

class Person {
    public dynamic Name { get; set; }
    public dynamic Address { get; set; }
}
class Address {
    public dynamic Number { get; set; }
    public dynamic Street { get; set; }
    public dynamic City { get; set; }
    public dynamic State { get; set; }
    public dynamic Country { get; set; }
    public override string ToString() {
        return String.Format("Number {0} {1}, \n {2}", this.Number, this.Street, this.City);
    }
}
var p1 = new Person();
var p2 = new Person();

p1.Address = "Number 17 Cherry Tree Lane";

p2.Address = new Address {
    Number = "17",
    Street = "Cherry Tree Lane",
    City = "London",
};

And if I run this in a console, I get precisely the same effect:

Number 17, Cherry Tree Lane  # <-- p1
17 Cherry Tree Lane  # <-- p2
London

Let's stop and take a breath. I know I've lost a lot of you... and that's OK. It's an appropriate time to address the following comment:

C# is a typed language; always has been, always will be.

and

If you find yourself using "var" anywhere that's not within a LINQ statement, it's probably not a good idea.

Ahh - the fun things you write about that end up being wrong. Yep - that was me said them words. The point of the post above was more that people were taking to the "var" keyword and calling it "duck typing" - which I still stand by: It's not. However I went on to say that using "var" everywhere will make your typed code look unreadable.

I was pretty wrong - what it did do was make my code much easier to refactor. I'm sure you've experienced this: being thankful that you're using "var" to work up a variable from a method return - you change that method return but you don't have to change the variable declaration. This is particularly nice when you work with an IEnumerable - the loop can just work, and maybe you just changed your method from IQueryable to IList...

If you've felt that feeling of freedom - hold on to your hats. This can get a whole lot more interesting. Or worse, depending on your perspective.

It's Anders' World. We Just Code Here

We've just barely touched on the dynamic "flavor" of coding dynamic-style. When you're writing code with Ruby, as I've mentioned, you care a lot more about what an object can do rather than what it *is*.

For instance - using a typed-approach, we would care that "p1.address" is an "Address" type so we should be able to do things with it like format a nice output and perhaps do some geo-locating with lat/lon.

We might kick up intellisense or the ObjectBrowser and get to know Address - see what it can do. Perhaps read sample code, or maybe inherit from it so we can add properties as we like.

With a more dynamic approach, what the object is doesn't matter. Just because it's an Address isn't the important part - it's whether it will give us a latitude/longitude coordinate. So let's ask it:

if(p1.address.respond_to? 'geo_locate')
  #do stuff
end

This approach allows you to do a lot of things - primarily to change completely the class that sits on Person. You're not depending on properties being there, named a certain way.

We should be able to do this with C# as well:

public static class DynamicExtensions {
    public static bool RespondTo(this dynamic thing, string name) {
        var found = thing.GetType()
            .GetMethods()
            .SingleOrDefault(x => x.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
        return found != null;
    }
}

But this won't compile - for good reason. Jon Skeet explains:

From the "New Features in C# 4" word doc: Dynamic lookup will not be able to find extension methods. Whether extension methods apply or not depends on the static context of the call (i.e. which using clauses occur), and this context information is not currently kept as part of the payload.

Bummer. Well maybe there's another way to interrogate the C# Address class - instead of "dynamic" - I'll just set it to "object" see if it works:

Double bummer. That's OK - I can get whimsical with this. By the way I'm searching up and down for a better way to do "meta stuff" and I've found a few articles - but they're just a bit confusing.

Now I'm curious. Ultra curious - how can I pry meta information out of a dynamic object? It seems that it's a Sixth Sense kind of thing - the object *doesn't know* it's a DynamicObject - so how I can interrogate it? Let's try directly:

static bool RespondTo(DynamicObject thing, string methodName) {
    return thing.GetDynamicMemberNames()
        .SingleOrDefault(x => x.Equals(methodName, StringComparison.InvariantCultureIgnoreCase)) != null;
}

Triple Bummer:

Makes perfect sense. Not really: the object isn't a DynamicObject anymore - it's an Address (or a string, depending). So we're kind of stuck here - right in the middle of compiler/dynamic land - with the compiler pretending it can be dynamic.

I can't use ExtensionMethods here because even if I try to extend object - at compile time the *property* is a DynamicObject - so that doesn't work. I can't get my meta on at runtime because the compiler thinks this thing is now an address and my method takes a DynamicObject...

There's a lot of thrashing possible at this point - the answer here (as you've probably guessed) is that I'm trying to solve this problem in a typed world. I need to get a b it more Dynamic.

Dynamic Dynamite

What needs to happen here is that *all* my objects need to be dynamic - and I overlooked that with my top-level classes, Person and Address. I'm going to use a base class here, as ugly as it seems, because I want to imbue the object with some meta love:

public class DynamicBase : DynamicObject {
  public bool RespondTo(string call) {
      return this.GetType().GetMethods()
          .SingleOrDefault(x => x.Name.Equals(call, StringComparison.InvariantCultureIgnoreCase)) != null;
  }
}

There's a lot more I can do here to approximate Ruby - things like MethodMissing delegates and Send - but this post is long enough.

Now I can just ask, and my object answers (after I've added the "GeoLocate" method):

And when I want to use it I can simply do this:

if(p2.Address.RespondTo("GeoLocate")){
  p2.Address.GeoLocate();
}

Discussion

A number of things are probably going through your head - and I'm going to guess that many will either kind of dig this or really, really hate it. It's worth a discussion - so without pinning me for doing bad things, I'd love to know what you think.

An interesting aspect of all this is that for most C# developers, this type of programming is pretty new. For Ruby/Python/Javascript devs - this is just how you do it (for the most part). As I've mentioned: the focus is less about what type something is - more about what it can do. This frees you tremendously, but you also lose something.

If you start to play around with dynamic, as I've done, you'll notice that you lose intellisense rather quickly. In the example I gave here - it's completely gone for Address and all of its properties and methods.

Moreover the VisualStudio coding experience starts to go away - the tooling can't really make heads or tails of what it is you're doing, so things like Linq to SQL and the EF design surface will most likely explode (I haven't tried it yet but...) anything that relies on types for a design-time experience is going to fail.

So what of it? A lot of people will intone "right tool for the right job" and "anything can be abused" - of course these statements are always true. Yet is there a time - a *better* time where "dynamic" is better than using types? Ayende put it to me this way:

In C#, we have types, and it is considered polite to use them, because that gives you much better API.

and...

API that fail early with compilation error is good. API that gives you support for intellisense is good. Given two APIs that express the same thing, I would take the one that uses strong typing any time.

Note that I don't necessarily disagree with this sentiment - I do disagree that intellisense and types make for a better API - but that's for another post.

If you feel Ayende is correct - when, in your mind then, is it OK to use dynamic? When is "the right time" in C#?

More importantly - C# is trending more and more into the Dynamic end of things. Coding like you're seeing here is going to become more and more prevalent. What do you think of this?

Microsoft suggests that working with System.Dynamic can happen when you work with individually unique objects at runtime - things like HTML DOMs - and also when running interop with other languages such as IronRuby/IronPython.

Events of late call into question the commitment to the DLR (not the first time) - and sidestepping that whole discussion - do you find these reasons compelling?

If you don't - what are your reasons for using System.Dynamic?