C# "dynamic"


PDC 2008 arrives today, and that means that I am finally able to talk publicly about some of the things I’ve been working on for the next version of C#. What a relief! I am excited for the world to see some of this stuff, and to start receiving more customer feedback about it.


This afternoon, Anders Hejlsberg presented a talk called “The Future of C#” that I confess I have not seen a dry-run of. I’m sure it went fabulously, though. In that talk, he introduced the “dynamic” feature in C# 4. The short story is that we plan to allow users to perform operations, the details of which are not known until runtime, using the dispatch mechanism supported by the DLR (Jim Hugunin is giving another talk today called “Deep Dive: Dynamic Languages in Microsoft .NET”).


Charlie Calvert and Mads Torgersen let slip a few months ago that this was coming, and at the time we got a lot of feedback about the particulars of that proposal (which you might like to go back and look at, but keep in mind that it is out-dated). In fact, we’ve been through a number of designs, and we’ve implemented a prototype and a few false starts before we settled on what we believe is the best design: dynamic is a type.


The type “dynamic”


So here’s an example of what you might see in C# 4, the result of which is a runtime/late-bound dispatch to the method “Foo” on some local variable:

dynamic d = GetADynamicThing();
d.Foo();

As you can see, the local variable “d” is of type dynamic, which is a proper type supported by the compiler, and which you can mention in most places that you can mention a type. This code compiles, and it would have compiled no matter what method name you had used. In that sense, “dynamic” is a very special type. It appears to support almost any method name, any property or field, in fact, most anything that you could do with some variable, you can do with a dynamic variable.


The difference of course is that instead of emitting an IL call to something called Foo, which the compiler clearly cannot do since there is no type involved that defines anything called Foo, the compiler emits a “dynamic call site” that manages that operation at runtime, using the C# Runtime binder in conjunction with the DLR, both of which are library components. More details on this later.


This allows you to use the C# language, with the brevity and syntax you’ve become accustomed to, to invoke methods on python or ruby objects, or on any COM IDispatch object, even without an interop assembly, or on any other object that “knows how to dispatch itself” (you could imagine, say, a DOM that uses this to expose its content as properties). And you can do this on regular old .NET objects too.


And since dynamic is a type, you can use it in more that just locals. For example, this compiles:

class C
{
public dynamic myField;
public dynamic MyProp { get; set; }
public dynamic MyMethod(dynamic d)
{
return d.Foo();
}
public delegate dynamic MyDelegate(dynamic d);
}

If you were to get the value of MyProp from some instance of C, and then do anything to it (maybe you could call the method Foo?), then that would be a dynamic dispatch.


A little behind-the-scenes


There is a lot going on here that I am omitting, the details of which I plan to bore/fascinate you with over the course of the next few weeks. Let me at least show you what one of these things looks like if we crack open the assembly. Assume the following class definition:

class C
{
public dynamic MyMethod(dynamic d)
{
return d.Foo();
}
}

That’s one method that includes some dynamic params as well as a single “dynamic call site” to call the method Foo. Reflector tells you that the assembly actually looks something like this (simplified a bit):

class C
{
[return: Dynamic]
public object MyMethod([Dynamic] object d)
{
if (MyMethodo__SiteContainer0.p__Site1 == null)
{
MyMethodo__SiteContainer0.p__Site1 =
CallSite<Func<CallSite, object, object>>
.Create(new CSharpCallPayload(
CSharpCallFlags.None, “Foo”, typeof(object), null,
new CSharpArgumentInfo[] {
new CSharpArgumentInfo(CSharpArgumentInfoFlags.None,
null) }));
}
return MyMethodo__SiteContainer0.p__Site1
.Target(MyMethodo__SiteContainer0.p__Site1, d);
}

[CompilerGenerated]
private static class MyMethodo__SiteContainer0
{
public static CallSite<Func<CallSite, object, object>> p__Site1;
}
}


As you can see, the publicly visible members that use the type dynamic actually, behind the scenes, use the type object when they are emitted. There is no framework type “dynamic.” However, those “objects” are all decorated in such a way that the compiler (or anyone else) can tell that they are meant to be handled dynamically.


There is also a static field to hold one of the DLR’s dynamic call sites for each dynamic operation that you perform. In this case, there is just one, and it corresponds to the method call to Foo. It is initialized inline with the code that uses it in a lazy manner, and invoked with the “Target” field which is actually a delegate that does the right work.


I admit that code looks scary! But the important thing is that it’s something that you don’t have to write. The compiler does it all for you. Again, lots of detail is being left out here–for instance, what really happens at runtime, the perf characteristics, and lots of juicy language considerations–but we’ll get to all that later.


A scenario we made better by all this


I want to end this post by responding to something that Scott Hanselman posted a little while ago, about the pain of programming against COM in C#. Go look at this post:



http://www.hanselman.com/blog/BackToBasicsVarDim.aspx


…and consider the 53-line horror of what you need to write to talk to Word via its COM object model. In C# anyway. Especially the last half, where there are a few calls to “InvokeMember.” Well, one of the benefits we get from the dynamic feature is that all this InvokeMember nonsense is no longer required. Check out the same 53 lines in C# 4 (now considerably smaller):

ApplicationClass WordApp = new ApplicationClass();
WordApp.Visible = true;
string fileName = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory, @”..\..\..\NewTest.doc”);
Document aDoc = WordApp.Documents.Open(
fileName, ReadOnly: false, Visible: true);

aDoc.Activate();

string propertyValue =
aDoc.CustomDocumentProperties[“CustomProperty1”].Value;
aDoc.CustomDocumentProperties[“CustomProperty1”] = “Hanselman”;

foreach (Range r in aDoc.StoryRanges)
{
r.Fields.Update();
}


If you look closely, you’ll notice that we don’t even mention the dynamic keyword in this code snippet. It comes in anyway, though, given that we import COM interop interfaces specially so that you automatically get dynamic calls where appropriate.


If you look closely again, you’ll see that there’s more here than just dynamic. How about that syntax on the Open() call? More on that later.


Like I said above several times, there’s a lot about this that I’ve left unsaid, and in fact there are a few bits that are even yet-undesigned. I’ll follow up with more information soon. If you have feedback or questions, please let me know! And happy PDCing if you’re in LA this week.


PS, I feel obliged to tell you that this post describes a product that has not shipped and is not yet complete. I cannot make any claim to know exactly what C# 4 will look like when it does ship. The code here corresponds roughly to what you can do with the PDC 2008 release of Visual Studio 2010 CTP. This posting is provided “AS IS” with no warranties, and confers no rights.

Comments (34)

  1. Well, I intended to spend the last three weeks blogging about C# design process in anticipation of our

  2. Yesterday, I made an attempt to introduce the C# dynamic feature by describing what change there has

  3. configurator says:

    (This has been cross-posted from http://www.codethinked.com/post/2008/10/28/C-40-New-Features-Part-1-dynamic-keyword.aspx )

    I wonder what would happen if I do this:

    dynamic test = new TestClass();

    test.TestMethod1();

    test = new TestClass2();

    test.TestMethod1();

    where both classes have TestMethod1 defined.

    Then, <Main>o__SiteContainer0.<>p__Site1 would be defined after the first call, and would be calling a wrong function after setting the dynamic variable to a different value.

    Of course, I haven’t seen or installed the CTP so I wouldn’t know the exact implications.

    ozone, the difference is that var is still bound at compile time. the line

    var test = new TestClass1();

    is translated into

    TestClass1 test = new TestClass1();

    You can see that using reflector.

    However, dynamic is translated to object, and changes every usage of that variable, as seen in the example given by Justin.

  4. Steve says:

    Curious about some implications.

    Can you nest dynamics as in dynamic x; x.Prop.Func()?

    Can you make a List<dynamic>?

    Thanks!

  5. Here are a few good resources that you ought to look at for information about dynamic from PDC: Anders

  6. The other day I was playing around with some office code, and I found myself writing a lot of code much

  7. Tanveer Badar says:

    VB with a syntax of C. Or C# without option strict.

    I really can’t make up my mind.

  8. cburrows says:

    Steve,

    Yes and yes. The result of dynamic operations are typed as dynamic, so you can layer them (except conversions, which are typed appropriately). And you can build generic types with dynamic too. I’ll talk more about this later.

    Tanveer,

    You’re right that this is something that VB has done, in a way, for a while. At least one difference is that you get to control it at a finer granularity than "option strict off," which affects your whole compilation unit as I understand it. Another difference is that we target the DLR, not the VB runtime.

    chris

  9. Anonymous says:

    Seems to me C# is really heading in the wrong direction. Up to 2.0 and some of 3.0 everything was amazing and perfect. Everything was designed perfectly, to where it constrained developers to also design accordingly and to follow rules. This in turn made errors much easier to find especially at compile time (Generics). Now, it seems as if we’re just throwing all this out the window and trying to just add every little convenient feature anybody can think up. It’s making the framework very messy and it’s going to result in less compile time errors caught and more run time errors…

  10. David Nelson says:

    I am trying really hard not to pre-judge, but I have to say that so far I haven’t seen anything that makes me think that the "dynamic" type is a good idea. I understand that dynamic languagues are becoming more popular, but that doesn’t mean that every language in the world needs to support dynamic typing. Different languages exist for different reasons and cater to different needs. It is not possible for one language to do everything, no matter how much the C# team might want to believe that. There are already projects underway to bring existing dynamic languages into the .NET world, and for that matter VB.NET is already capable of late binding when it is necessary for things like COM compatability. Did the C# team somehow feel the need to compete with these languages? Did they forget the core principles which have made C# so successful? It would have been a far better choice to make the language MORE strict, using the great features being developed in Spec#, rather than trying to build in this dynamic capability which adds little value and carries with it the very real possibility of seriously diluting the language.

    C# is based on static typing for a reason; tossing that out the window for the sake of the latest fad is irresponsbile at best.

  11. int19h says:

    Did the C# team somehow feel the need to compete with these languages?

    I think you’re missing the point. C# is not trying to compete with these languages, it’s trying to interoperate with them. With C# 4.0, I can write a class library in Python or Ruby, and then use it from C#, whereas before, it could only be the other way around. And this is cool.

  12. evildude says:

    Why anybody in right mind would write class library in Python or Ruby?

  13. Mark Rendle says:

    Does this new dynamic stuff include an "eval" of any sort?

  14. Dolgov V. says:

    It’s a very bad idea.

    C# 1.0 aim to more strict and safe code. Even unboxing (if variable’s type was "object") can’t be made without explicit type convertion. But now, in C# 4.0, it’s can.

    And such simple use of Python or/and Ruby libraries in C# is the way to minefield of errors.

  15. Welcome to the 47th Community Convergence. We had a very successful trip to PDC this year. In this post

  16. Mark Rendle says:

    It’s quite possible to create a minefield of errors in C# already, if you’re a bad enough programmer. If you’re a good programmer, and you cover your code with unit tests, then there’s no reason why dynamic code should be any more error-prone than static code.

    If C# 4.0 was becoming a fully dynamic language, I’d be at Microsoft’s gates (NPI) with pitchforks and torches. But all it’s doing is adding a new type and some compiler support, and hugely simplifying a multitude of tasks, not least Office interop. That’s got to be a good thing.

  17. David Nelson says:

    @Dolgov

    Explicit casting is required any time you cast down the type hierarchy, which is what you’re doing when you cast from "object" to a value type; boxing and unboxing was a side effect that was handled automatically by the compiler.

    @Mark

    "If you’re a good programmer, and you cover your code with unit tests, then there’s no reason why dynamic code should be any more error-prone than static code."

    You’re right, tests are great. And compile-time type checking is just another kind of test, one that the compiler won’t let you turn off. Why would I voluntarily eliminate an entire class of tests that is available to me, and hope that the tests that I have written myself cover all the possible problems that the compiler could have caught for me?

    "It’s quite possible to create a minefield of errors in C# already,"

    Its quite possible for an idiot to create a minefield out of anything, and that applies to every area of life, not just programming. How to deal with idiots is not germane to the discussion. The question is, how do we help competent, well-intentioned developers "fall into the pit of success"? Making things more dynamic doesn’t move us any closer to that goal, it pushes us farther away.

  18. int19h says:

    Thankfully, C# these days is not similar to Java in that it does not try to be as idiot-proof as possible by severely limiting its features. Yes, "dynamic" can be misused. So can lambdas, generics, partial classes/methods, and God knows what else. But in the right hands they’re all great and useful tools, and that’s what is important.

  19. Mark says:

    David, repeat after me: COMPILATION IS NOT TESTING.

  20. David Nelson says:

    Mark,

    Semantic compile-time errors such as type checking serve the exact same purpose as unit testing typically does in dynamic languages. I just choose to use the C# compiler to do that first step in the testing for me, rather than throwing out all of those checks that are already built in and then trying to recreate them (DRY anyone?).

  21. Dolgov V. says:

    @David

    "Explicit casting is required any time you cast down the type hierarchy, …"

    Yes, of cause. When we use static typing.

    But with dynamic I can write

    dynamic a = new Animal();

    Duck d = a;

    with no compile errors.

  22. Today, let’s geek out about the language design regarding the dynamic type. Type in the language vs.

  23. odahan says:

    I’m just hoping (dreaming?) that C#4 dynamic feature will be OFF by default. And to switch it ON I propose to hide the parameter very deep in a crypted xml config file with a bizzare name. Of course a very long password will be necessary to decrypt the config file and change the switch to ON. The very long password will only be accessible opening an account on a very expensive MS portail.

    If all those conditions are ok for you, then I’m ok for the dynamic implementation in C# 4 !

  24. Alex G says:

    Funny how people complain at every new C# feature. Remember back in the pre 3.0 days when people complained of lambda/closure…

    There’s no motivation for a developer to use dynamic unless there is a real need, so I don’t see a problem. It’s like some of you are affraid us C# programmers will think we’re supposed to scrap all type declarations and use dynamic everywhere…

    Well truly, it is you sunday morning theorists that scare me.

    Thanks to the C# team for making our lives simpler when it comes to interoperability.

    Next time I hear office integration, I might want to hurt someone for suggesting we install office in the server farm, but at least not for suggesting we interop with it from C# 🙂

  25. David Nelson says:

    @Alex,

    I don’t remember there being a significant uproar about lambdas or closures. They were somewhat misunderstood, but I don’t remember seeing a lot of people arguing that they should not be added to the language.

    The problem with dynamic is that there are many C# developers, especially those reluctantly converted from VB, who WILL think they are supposed to scrap all type declarations and use dynamic everywhere! I am NOT saying that simply having a potential for misuse is a reason not to add a feature to a language; I am sick of having my objections cast in that light. What I AM saying is that I don’t believe that the feature as it is currently implemented brings enough added value to the language to outweigh the negative effects it will have. I also believe that there were other options for implementing late binding which would fit better into a statically typed language.

  26. Let’s look at this: dynamic d = null ; object o = d; // not an implicit conversion Last time , I said

  27. We left off last time with this piece of code public class C { public static void M( int i) { } public

  28. Very good resources for the coming version… Sam Ng Dynamic in C# Part One Dynamic in C# Part Two Chris

  29. Bob Reselman says:

    This sounds really cool.

    Tell me please, what is the real world benefit? I am afraid that this is a reintroduction of the VB Variant. But, somehow I think that it is not. I wish that understood this better.

  30. dracoon says:

    Instead dynamic,

    can’t u make a lot better performance of unboxing operation ?

  31. When I wrote my Excel financial library I agonized over the decision of which numeric type to use to

  32. CodeClimber says:

    ASP.NET MVC for RoR developers: do as locals do

  33. It has been a while since I posted anything here, and I have the same excuse everyone else does. Work,

  34. Normal 0 21 false false false FR X-NONE X-NONE Let&rsquo;s have a look to see what the tool NDepend shows