Dynamic binding vs type inference - c#

In The C# Programming language Bill Wagner says:
Many people confuse dynamic binding with type inference. Type
inference is statically bound. The compiler determines the type at
compile time. For example:
var i = 5; //i is an int (Compiler performs type inference)
Console.WriteLine(i); //Static binding to Console.WriteLine(int)
The compiler infers that i is an integer. All binding on the variable
i uses static binding.
Now, given this information and my own made-up dynamic scenerio:
dynamic i = 5; //Compiler punts
Console.WriteLine(i);//This is now dynamically bound
We know type inference is statically bound. This implies that there is no way a dynamic variable can use type inference to determine a type. How does a dynamic type get resolved without using type inference?
Update
To try and clarify...at runtime we must somehow figure out what type i is right? Because I assign a literal 5 then the runtime can infer that i is an int. Isn't that type inference rather than dynamic binding?

What distinction is Bill making?
The distinction that Bill is making is that many people think that:
var x = Whatever();
x.Foo();
will work out at runtime what method Foo to call based on the type of object returned at runtime by Whatever. That's not true; that would be
dynamic x = Whatever();
x.Foo();
The var just means "work out the type at compile time and substitute it in", not "work it out at runtime".
So if I have
dynamic i = 5;
Console.WriteLine(i);
What happens?
The compiler generates code that is morally like this:
object i = (object)5;
DynamicCallSite callSite = new DynamicCallSite(typeof(Console), "WriteLine"));
callSite.Invoke(i);
It is a bit more complicated than that; the call site is cached, for one thing. But this gives you the flavour of it.
The invocation method asks i for its type via GetType and then starts up a special version of the C# compiler that can understand reflection objects. It does overload resolution on the members of Console named WriteLine, and determines which overload of Console.WriteLine would have been called had i been typed as int in the first place.
It then generates an expression tree representing that call, compiles the expression tree into a delegate, caches it in the call site, and invokes the delegate.
The second time you do this, the cached call site looks in its cache and sees that the last time that i was int, a particular delegate was invoked. So the second time it skips creating the call site and doing overload resolution, and just invokes the delegate.
For more information, see:
http://ericlippert.com/2012/10/22/a-method-group-of-one/
http://ericlippert.com/2012/11/05/dynamic-contagion-part-one/
http://ericlippert.com/2012/11/09/dynamic-contagion-part-two/
A historical perspective on the feature can be obtained from Chris and Sam's blogs:
http://blogs.msdn.com/b/cburrows/archive/tags/dynamic/
http://blogs.msdn.com/b/samng/archive/tags/dynamic/
They did a lot of the implementation; however some of these article reflect outdated design choices. We never did go with "The Phantom Method" algorithm, regrettably. (Not a great algorithm, but a great name!)

Related

Using a dynamic variable as a method argument disables (some) compiler checks

Can someone explain to me why the compiler does not check the return type of a function if a dynamic variable is used as an argument to a method call?
class Program
{
static void Main(string[] args)
{
// int a = GetAString(1); // Compiler error CS0029 Cannot impilicitly convert type 'string' to 'int'
dynamic x = 1;
int b = GetAString(x); // No compiler error -> Runtime Binder Exception
// int c = (string)GetAString(x); // Compiler error CS0029 Cannot impilicitly convert type 'string' to 'int'
}
static string GetAString(int uselessInt)
{
return "abc";
}
}
By using dynamic the compiler will generate a call site anywhere you use a dynamic parameter. This call site will attempt to resolve the method at runtime, and if it cannot find a matching method will raise an exception.
In your example the call site examines x and sees that it is an int. It then looks for any methods called GetAString that take an int and finds your method and generates code to make the call.
Next, it will generate code to attempt to assign the return value to b. All of this is still done at runtime as the use of the dynamic variable has made the entire expression require runtime evaluation. The call site will see if it can generate code to assign a string to an int, and as it cannot it will raise an exception.
As an aside, your example doesn't make a lot of sense as you seem to want to assign a string to an int Your GetAsString method is even returning a non-numeric value so it's never going to assign to an int. If you write:
dynamic x = 1;
string b = GetAsString(x);
Then everything should work.
In the general case, the candidates aren't necessarily as straightforward as yours. For example, consider these two methods:
string M(string a) => a;
char[] M(char[] a) => a;
What should this code suggest as the type of the last variable?
dynamic d = SomeExpression();
var s = M(d);
At this point, the designers of C# would have to make a choice:
Assert that the return value of a method called with dynamic arguments is also dynamic itself.
Select a type that can be assigned from all methods of the group (e.g. IEnumerable<char>).
The latter option is essentially what you're describing in your question. The C# designers went with the former option. Possible reasons for that design decision could be:
Maybe they thought that if you opt in to dynamic in an expression, then it's more likely than not that you'll want to keep using dynamic on any dependent expressions, until you explicitly opt out of it again.
Maybe they didn't introduce dynamic to enable multiple dispatch, so they didn't want to encourage it further by including provisions for static typing.
Maybe they thought that including those provisions would bloat the specification or make the language harder to understand.
Maybe the former option is simpler to implement (assuming you already have the rest of dynamic implemented) and they decided the other option wasn't worth more time or effort.
Maybe it's just not that straightforward to implement in C#. Value types could require boxing to match the common supertype, which complicates things. Raw pointer types are out of the unified hierarchy altogether.

Why does a method invocation expression have type dynamic even when there is only one possible return type?

Inspired by this question.
Short version: Why can't the compiler figure out the compile-time type of M(dynamic arg) if there is only one overload of M or all of the overloads of M have the same return type?
Per the spec, §7.6.5:
An invocation-expression is dynamically bound (§7.2.2) if at least one of the following holds:
The primary-expression has compile-time type dynamic.
At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type.
It makes sense that for
class Foo {
public int M(string s) { return 0; }
public string M(int s) { return String.Empty; }
}
the compiler can't figure out the compile-time type of
dynamic d = // dynamic
var x = new Foo().M(d);
because it won't know until runtime which overload of M is invoked.
However, why can't the compiler figure out the compile-time type if M has only one overload or all of the overloads of M return the same type?
I'm looking to understand why the spec doesn't allow the compiler to type these expressions statically at compile time.
UPDATE: This question was the subject of my blog on the 22nd of October, 2012. Thanks for the great question!
Why can't the compiler figure out the compile-type type of M(dynamic_expression) if there is only one overload of M or all of the overloads of M have the same return type?
The compiler can figure out the compile-time type; the compile-time type is dynamic, and the compiler figures that out successfully.
I think the question you intended to ask is:
Why is the compile-time type of M(dynamic_expression) always dynamic, even in the rare and unlikely case that you're making a completely unnecessary dynamic call to a method M that will always be chosen regardless of the argument type?
When you phrase the question like that, it kinda answers itself. :-)
Reason one:
The cases you envision are rare; in order for the compiler to be able to make the kind of inference you describe, enough information must be known so that the compiler can do almost a full static type analysis of the expression. But if you are in that scenario then why are you using dynamic in the first place? You would do far better to simply say:
object d = whatever;
Foo foo = new Foo();
int x = (d is string) ? foo.M((string)d) : foo((int)d);
Obviously if there is only one overload of M then it is even easier: cast the object to the desired type. If it fails at runtime because the cast it bad, well, dynamic would have failed too!
There's simply no need for dynamic in the first place in these sorts of scenarios, so why would we do a lot of expensive and difficult type inference work in the compiler to enable a scenario we don't want you using dynamic for in the first place?
Reason two:
Suppose we did say that overload resolution has very special rules if the method group is statically known to contain one method. Great. Now we've just added a new kind of fragility to the language. Now adding a new overload changes the return type of a call to a completely different type -- a type which not only causes dynamic semantics, but also boxes value types. But wait, it gets worse!
// Foo corporation:
class B
{
}
// Bar corporation:
class D : B
{
public int M(int x) { return x; }
}
// Baz corporation:
dynamic dyn = whatever;
D d = new D();
var q = d.M(dyn);
Let's suppose that we implement your feature requiest and infer that q is int, by your logic. Now Foo corporation adds:
class B
{
public string M(string x) { return x; }
}
And suddenly when Baz corporation recompiles their code, suddenly the type of q quietly turns to dynamic, because we don't know at compile time that dyn is not a string. That is a bizarre and unexpected change in the static analysis! Why should a third party adding a new method to a base class cause the type of a local variable to change in an entirely different method in an entirely different class that is written at a different company, a company that does not even use B directly, but only via D?
This is a new form of the Brittle Base Class problem, and we seek to minimize Brittle Base Class problems in C#.
Or, what if instead Foo corp said:
class B
{
protected string M(string x) { return x; }
}
Now, by your logic,
var q = d.M(dyn);
gives q the type int when the code above is outside of a type that inherits from D, but
var q = this.M(dyn);
gives the type of q as dynamic when inside a type that inherits from D! As a developer I would find that quite surprising.
Reason Three:
There is too much cleverness in C# already. Our aim is not to build a logic engine that can work out all possible type restrictions on all possible values given a particular program. We prefer to have general, understandable, comprehensible rules that can be written down easily and implemented without bugs. The spec is already eight hundred pages long and writing a bug-free compiler is incredibly difficult. Let's not make it more difficult. Not to mention the expense of testing all those crazy cases.
Reason four:
Moreover: the language affords you many opportunities to avail yourself of the static type analyzer. If you are using dynamic, you are specifically asking for that analyzer to defer its action until runtime. It should not be a surprise that using the "stop doing static type analysis at compile time" feature causes static type analysis to not work very well at compile time.
An early design of the dynamic feature had support for something like this. The compiler would still do static overload resolution, and introduced a "phantom overload" that represents dynamic overload resolution only if necessary.
Blog post introducing phantom methods
Details on phantom methods
As you can see in the second post, this approach introduces a lot of complexity (the second article talks about how type inference would need to be modified to make the approach work out). I'm not surprised that the C# team decided to go with the simpler idea of always using dynamic overload resolution when dynamic is involved.
However, why can't the compiler figure out the compile-time type if M has only one overload or all of the overloads of M return the same type?
The compiler could potentially do this, but the language team decided not to have it work this way.
The entire purpose of dynamic is to have all expressions using dynamic execute with "their resolution is deferred until the program is run" (C# spec, 4.2.3). The compiler explicitly does not perform static binding (which would be required to get the behavior you want here) for dynamic expressions.
Having a fallback to static binding if there was only a single binding option would force the compiler to check this case - which was not added in. As for why the language team didn't want to do it, I suspect Eric Lippert's response here applies:
I am asked "why doesn't C# implement feature X?" all the time. The answer is always the same: because no one ever designed, specified, implemented, tested, documented and shipped that feature.
I think the case of being able to statically determine the only possible return type of a dynamic method resolution is so narrow that it would be more confusing and inconsistent if the C# compiler did it, rather than having across the board behavior.
Even with your example, what if Foo is part of a different dll, Foo could be a newer version at runtime from a binding redirect with additional M's that have a different return type, and then the compiler would have guessed wrong because the runtime resolution would return a different type.
What if Foo is an IDynamicMetaObjectProvider d might not match any of the static arguments and thus it would fall back on it's dynamic behavior which could possibly return a different type.

Why calling ISet<dynamic>.Contains() compiles, but throws an exception at runtime?

Please, help me to explain the following behavior:
dynamic d = 1;
ISet<dynamic> s = new HashSet<dynamic>();
s.Contains(d);
The code compiles with no errors/warnings, but at the last line I get the following exception:
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'System.Collections.Generic.ISet<object>' does not contain a definition for 'Contains'
at CallSite.Target(Closure , CallSite , ISet`1 , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
at FormulaToSimulation.Program.Main(String[] args) in
As far as I can tell, this is related to dynamic overload resolution, but the strange things are
(1) If the type of s is HashSet<dynamic>, no exception occurs.
(2) If I use a non-generic interface with a method accepting a dynamic argument, no exception occurs.
Thus, it looks like this problem is related particularly with generic interfaces, but I could not find out what exactly causes the problem.
Is it a bug in the compiler/typesystem, or legitimate behavior?
The answers you have received so far do not explain the behaviour you are seeing. The DLR should find the method ICollection<object>.Contains(object) and call it with the boxed integer as a parameter, even if the static type of the variable is ISet<dynamic> instead of ICollection<dynamic> (because the former derives from the latter).
Therefore, I believe this is a bug and I have reported it to Microsoft Connect. If it turns out that the behaviour is somehow desirable, they will post a comment to that effect there.
Why it compiles: the entire expression is evaluated as dynamic (hover your mouse over it inside your IDE to confirm), which means that it is a runtime check.
Why it bombs: My (completely wrong, see below) guess is that it is because you cannot implement a dynamic interface in such a manner. For example, the compiler does not allow you to create a class that implements ISet<dynamic>, IEnumerable<dynamic>, IList<dynamic>, etc. You get a compile-time error stating "cannot implement a dynamic interface". See Chris Burrows' blog post on this subject.
http://blogs.msdn.com/b/cburrows/archive/2009/02/04/c-dynamic-part-vii.aspx
However, since it's hitting the DLR anyway, you can make s completely dynamic.
dynamic s = new HashSet<dynamic>;
s.Contains(d);
Compiles and runs.
Edit: the second part of this answer is completely wrong. Well, it is correct in that you can't implement such an interface as ISet<dynamic>, but that's not why this blows up.
See Julian's answer below. You can get the following code to compile and run:
ICollection<dynamic> s = new HashSet<dynamic>();
s.Contains(d);
The Contains method is defined on ICollection<T>, not ISet<T>. The CLR doesn't allow an interface base method to be called from a derived interface. You usually doesn't see this with static resolution because the C# compiler is smart enough to emit a call to ICollection<T>.Contains, not the non-existing ISet<T>.Contains.
Edit: The DLR mimics the CLR behavior, that's why you get the exception. Your dynamic call is done on an ISet<T>, not an HashSet<T> the DLR will mimics the CLR: for an interface, only interfaces methods are searched for, not base interfaces (contrary to classes where this behavior is present).
For an in-depth explanation, see a previous response of mine to a similar question:
Strange behaviour when using dynamic types as method parameters
Note that the type dynamic doesn’t actually exist at run-time. Variables of that type are actually compiled into variables of type object, but the compiler turns all the method calls (and properties and everything) that involve such an object (either as the this object or as a parameter) into a call that is resolved dynamically at runtime (using System.Runtime.CompilerServices.CallSiteBinder and related magic).
So what happens in your case is that the compiler:
turns ISet<dynamic> into ISet<object>;
turns HashSet<dynamic> into HashSet<object>, which becomes the actual run-time type of the instance you’re storing in s.
Now if you try to invoke, say,
s.Contains(1);
this actually succeeds without a dynamic invocation: it really just calls ISet<object>.Contains(object) on the boxed integer 1.
But if you try to invoke
s.Contains(d);
where d is dynamic, then the compiler turns the statement into one that determines, at runtime, the correct overload of Contains to call based on the runtime type of d. Perhaps now you can see the problem:
The compiler emits code that definitely searches the type ISet<object>.
That code determines that the dynamic variable has type int at runtime and tries to find a method Contains(int).
ISet<object> does not contain a method Contains(int), hence the exception.
ISet interface does not have a method 'Contains', HashSet does however?
EDIT
What i meant to say was the binder resolves 'Contains' when given the HashSet concreate type, but doesnt find the inherited 'Contains' method in the interface...

Why does this work?

Why does this work? I'm not complaining, just want to know.
void Test()
{
int a = 1;
int b = 2;
What<int>(a, b);
// Why does this next line work?
What(a, b);
}
void What<T>(T a, T b)
{
}
It works because a and b are integers, so the compiler can infer the generic type argument for What.
In C# 3, the compiler can also infer the type argument even when the types don't match, as long as a widening conversion makes sense. For instance, if c were a long, then What(a, c) would be interpreted as What<long>.
Note that if, say, c were a string, it wouldn't work.
The C# compiler supports type inference for generics, and also commonly seen if you are using the var keyword.
Here int is inferred from the context (a and b) and so <int> is not needed. It keeps code cleaner and easier to read at times.
Sometimes your code may be more clear to read if you let the compiler infer the type, sometimes it may be more clear if you explicitly specify the type. It is a judgement call on your given situation.
It's using type inference for generic methods. Note that this has changed between C# 2 and 3. For example, this wouldn't have worked in C# 2:
What("hello", new object());
... whereas it would in C# 3 (or 4). In C# 2, the type inference was performed on a per-argument basis, and the results had to match exactly. In C# 3, each argument contributes information which is then put together to infer the type arguments. C# 3 also supports multi-phase type inference where the compiler can work out one type argument, then see if it's got any more information on the rest (e.g. due to lambda expressions with implicit parameter types). Basically it keeps going until it can't get any more information, or it finishes - or it sees contradictory information. The type inference in C# isn't as powerful as the Hindley-Milner algorithm, but it works better in other ways (in particular it always makes forward progress).
See section 7.4.2 of the C# 3 spec for more information.
The compiler infers the generic type parameter from the types of the actual parameters that you passed.
This feature makes LINQ calls much simpler. (You don't need to write numbers.Select<int, string>(i => i.ToString()), because the compiler infers the int from numbers and the string from ToString)
The compiler can infer type T to be an int since both parameters passed into What() are of type int. You'll notice a lot of the Linq extensions are defined with generics (as IEnumerable) but are typically used in the manner you show.
If the subject of how this works in C# 3.0 is interesting to you, here's a little video of me explaining it from back in 2006, when we were first designing the version of the feature for C# 3.0.
http://blogs.msdn.com/ericlippert/archive/2006/11/17/a-face-made-for-email-part-three.aspx
See also the "type inference" section of my blog:
http://blogs.msdn.com/ericlippert/archive/tags/Type+Inference/default.aspx
The compiler is smart enough to figure out that the generic type is 'int'

Does the new 'dynamic' C# 4.0 keyword deprecate the 'var' keyword?

When C# 4.0 comes out and we have the dynamic keyword as described in this excellent presentation by Anders Hejlsberg, (C# is evolving faster than I can keep up.. I didn't have much time to acquaint myself with the var keyword)
Would I still need the var keyword ? Is there anything that var can do.. that dynamic can't?
var x = SomeFunctionThatIKnowReturnsSomeKindOfList();
// do something with x
dynamic x = SomeFunctionThatIKnowReturnsSomeKindOfList();
// do something with x
No, they're very different.
var means "infer the type of the variable at compile-time" - but it's still entirely statically bound.
dynamic means "assume I can do anything I want with this variable" - i.e. the compiler doesn't know what operations are available, and the DLR will work out what the calls really mean at execution time.
I expect to use dynamic very rarely - only when I truly want dynamic behaviour:
var lets you catch typos etc at compile-time
statically bound code is always going to run faster than dynamically bound code (even if the difference becomes reasonably small)
statically bound code gives more compile-time support beyond just errors: you can find call hierarchies, refactoring will work better, Intellisense is available etc
Dynamic and var represent two completely different ideas.
var
Var essentially asks the compiler to figure out the type of the variable based on the expression on the right hand side of the assignment statement. The variable is then treated exactly as if it were explicitly declared as the type of the expression. For example the following two statements are equivalent
var a = "foo";
string a = "foo";
The key to take away here is that "var" is 100% type safe and is a compile time operation
dynamic
Dynamic is in many ways the exact opposite of var. Using dynamic is essentially eliminating all type safety for thet particular variable. It many ways it has no type. When you call a method or field on the variable, the determination on how to invoke that field occurs at runtime. For example
dynamic d = SomeOperation();
d.Foo(); // Will this fail or not? Won't know until you run the program
The key to take away here is that "dynamic" is not type safe and is a runtime operation
Yes you will still need var:
Var is a variable whose type will be inferred by the compiler.
dynamic will have its type assigned at runtime
So:
Var i = "Hello World"
will have its type inferred as a string type in doing so intellisence will give you all the methods that string can use like,
i.Split("/")
Where as:
dynamic i = "Hello World"
won't have its type inferred untill runtime because the complier dosn't know what type it is yet, but will still let you do:
i.Split("/")
but when it calls the method that you need it may fail because the type is wrong and the method isn't there.

Categories