16

Does defining an instance as dynamic in C# mean:

  1. The compiler does not perform compile-time type checking, but run-time checking takes place like it always does for all instances.

  2. The compiler does not perform compile-time type checking, but run-time checking takes place, unlike with any other non-dynamic instances.

  3. Same as 2, and this comes with performance penalty (trivial? potentially significant?).

Timwi
  • 65,159
  • 33
  • 165
  • 230
FarahBoBarah
  • 171
  • 1
  • 4
  • 1
    Does this answer your question? [How does having a dynamic variable affect performance?](https://stackoverflow.com/questions/7478387/how-does-having-a-dynamic-variable-affect-performance) – StayOnTarget Dec 20 '19 at 16:01

6 Answers6

44

The question is very confusing.

Does defining an instance as dynamic in C# mean:

By "defining an instance" do you mean "declaring a variable"?

The compiler does not perform compile-time type checking, but run-time checking takes place like it always does for all instances.

What do you mean by "run-time checking like it always does"? What run-time checking did you have in mind? Are you thinking of the checking performed by the IL verifier, or are you thinking of runtime type checks caused by casts, or what?

Perhaps it would be best to simply explain what "dynamic" does.

First off, dynamic is from the perspective of the compiler a type. From the perspective of the CLR, there is no such thing as dynamic; by the time the code actually runs, all instances of "dynamic" have been replaced with "object" in the generated code.

The compiler treats expressions of type dynamic exactly as expressions of type object, except that all operations on the value of that expression are analyzed, compiled and executed at runtime based on the runtime type of the instance. The goal is that the code executed has the same semantics as if the compiler had known the runtime types at compile time.

Your question seems to be about performance.

The best way to answer performance questions is to try it and find out - what you should do if you need hard numbers is to write the code both ways, using dynamic and using known types, and then get out a stopwatch and compare the timings. That's the only way to know.

However, let's consider the performance implications of some operations at an abstract level. Suppose you have:

int x = 123;
int y = 456;
int z = x + y;

Adding two integers takes about a billionth of a second on most hardware these days.

What happens if we make it dynamic?

dynamic x = 123;
dynamic y = 456;
dynamic z = x + y;

Now what does this do at runtime? This boxes 123 and 456 into objects, which allocates memory on the heap and does some copies.

Then it starts up the DLR and asks the DLR "has this code site been compiled once already with the types for x and y being int and int?"

The answer in this case is no. The DLR then starts up a special version of the C# compiler which analyzes the addition expression, performs overload resolution, and spits out an expression tree describing the lambda which adds together two ints. The DLR then compiles that lambda into dynamically generated IL, which the jit compiler then jits. The DLR then caches that compiled state so that the second time you ask, the compiler doesn't have to do all that work over again.

That takes longer than a nanosecond. It takes potentially many thousands of nanoseconds.

Does that answer your questions? I don't really understand what you're asking here but I'm making a best guess.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Eric , what if `x,y` (assuming there is `+` operator) were reference types ? would the DLR behave the same as it is in your example ? – Royi Namir Mar 18 '13 at 10:21
  • 1
    Eric, thank you. Based on [this answer](https://stackoverflow.com/a/5038029/730566), is it safe to assume there would be no performance increase by using a `Dictionary` vs a `Dictionary` - as both would require boxing and unboxing of the dictionary value? For storing Generic types in a Dictionary – Adam Plocher Jan 22 '20 at 20:44
  • 3
    @AdamPlocher: There is no difference whatsoever between the type `X` and the type `X` from the perspective of the runtime; by the time we get to runtime, `dynamic` has been erased and replaced with `object`. The difference is entirely in the code that would be generated by the compiler when you *use* the dictionary; `d[foo].bar()` would be an error if the dictionary value type were `object`. If it were `dynamic` then this would be legal and the call to `bar` would be analyzed at runtime. – Eric Lippert Jan 22 '20 at 21:31
  • 2
    @AdamPlocher: If you are worried about the boxing penalty of storing an `int` value in a dictionary of objects, you'll get the same penalty storing an `int` value in a dictionary of dynamics. Again, **dynamic is just object wearing a funny hat**. It is "object, but defer further analysis of this expression until runtime". – Eric Lippert Jan 22 '20 at 21:33
6

As far as I know, the answer is 3.

You can do this:

dynamic x = GetMysteriousObject();
x.DoLaundry();

Since the compiler does no type checking on x, it will compile this code, the assumption being that you know what you're doing.

But this means extra run-time checking has to occur: namely, examining x's type, seeing if it has a DoLaundry method accepting no arguments, and executing it.

In other words the above code is sort of like doing this (I'm not saying it's the same, just drawing a comparison):

object x = GetMysteriousObject();

MethodInfo doLaundry = x.GetType().GetMethod(
    "DoLaundry",
    BindingFlags.Instance | BindingFlags.Public
);

doLaundry.Invoke(x, null);

This is definitely not trivial, though that isn't to say you're going to be able to see a performance issue with your naked eye.

I believe the implementation of dynamic involves some pretty sweet behind-the-scenes caching that gets done for you, so that if you run this code again and x is the same type, it'll run a lot faster.

Don't hold me to that, though. I don't have all that much experience with dynamic; this is merely how I understand it to work.

Servy
  • 202,030
  • 26
  • 332
  • 449
Dan Tao
  • 125,917
  • 54
  • 300
  • 447
  • Quick question which is not relevant to this question tho but What's `BindingFlags` used for? – Tarik Sep 24 '10 at 05:26
  • 3
    @Braveyard: It's basically a set of flags used to specify what characteristics apply to a certain reflected member. In the example above, the relevant characteristics are that it is a public instance member. If `DoLaundry` were a static method, for example, the above code would not find it (you'd need to add `BindingFlags.Static`). – Dan Tao Sep 24 '10 at 05:36
  • Things get a bit more complicated too if a dynamic object is passed as an argument to a function that takes non-dynamic perameters, especially one that has multiple overloads. – Jeff Mercado Sep 24 '10 at 08:25
  • @Timwi: Good call -- I was honestly taking a shot in the dark. In retrospect, guessing the JIT compiler really didn't make much sense. – Dan Tao Sep 24 '10 at 12:58
3

Declaring a variable as dynamic is similar to declaring it as object. Dynamic simply gets another flag indicating that member resolution gets deferred to run-time.

In terms of the performance penalty - it depends on what the underlying object is. That's the whole point of dynamic objects right? The underlying object can be a Ruby or Python object or it can be a C# object. The DLR will figure out at run-time how to resolve member calls on this object and this resolution method will determine the performance penalty.

Having said that - there definitely is a performance penalty.

That's why we're not simply going to start using dynamic objects all over the place.

Jaco Pretorius
  • 24,380
  • 11
  • 62
  • 94
  • There are a few notable difference such as there's only four methods you Can call when declaring as object and I'd be (unless customized binding is in play) if the type of the object played a significant role in the perormance penalty – Rune FS Sep 24 '10 at 05:46
1

Well, the variable is statically typed to be of the type dynamic but beyond that the compiler doesn't do any checking as far as I know.

Type binding is done at runtime and yes, there's a penalty, but if dynamic is the only option then so what. If you can solve the problem using static typing do so. That being said, the DLR does call site caching which means some of the overhead is reduced as the plumbing can be reused in some cases.

Servy
  • 202,030
  • 26
  • 332
  • 449
Brian Rasmussen
  • 114,645
  • 34
  • 221
  • 317
1

I made a simple test: 100000000 assignments to a variable as a dynamic vs. the same number of direct double assignments, something like

int numberOfIterations = 100000000;

Stopwatch sw = new Stopwatch();
sw.Start();

for (int i = 0; i < numberOfIterations; i++)
{
    var x = (dynamic)2.87; 
}

sw.Stop();
sw.Restart();

for (int i = 0; i < numberOfIterations; i++)
{
    double y = 2.87; 
}
sw.Stop();

In the first loop (with dynamic) it took some 500ms; in the second one about 200ms. Certainly, the performance loss depends of what you do in your loops, these representing a simplest action possible.

Alex Konnen
  • 717
  • 6
  • 20
-3

As far i undesrtand dynamic it only bypasses compile time check. resolution of type happens at runtime as it does for all types. so i dont think there is any performance penalty associated with it.

Servy
  • 202,030
  • 26
  • 332
  • 449
Vinay B R
  • 8,089
  • 2
  • 30
  • 45
  • The two are far from each other at runtime with a performance hit. E.g. With dynamic the compiler needs to make method overload resolution to see which method to Call and fail if it doesn't find any – Rune FS Sep 24 '10 at 05:39