Question

Why does the following compile? It sure seems like the compiler has enough info to know that the attempted assignment is invalid, since the return type of the Func<> is not dynamic.

Func<dynamic, int> parseLength = whatever => whatever.Length;
dynamic dynamicString = "String with a length";
DateTime wrongType = parseLength(dynamicString);
Was it helpful?

Solution

It sure seems like the compiler has enough info to know that the attempted assignment is invalid, since the return type of the Func<> is not dynamic.

Caveat: Of course I no longer speak for the C# design team; these are my opinions on language design.

So what you're saying here is "I've disabled a safety system. Why isn't the disabled safety system detecting when I do something dangerous and stopping me?" Well, if that's what you wanted then maybe you shouldn't have disabled that safety system in the first place.

That said, you are correct; the "disabled" type safety system could actually continue to work here and detect that you're doing something dangerous. In fact there are many situations where a sufficiently clever compiler could make a type deduction about a dynamic subexpression. You've found one of them. Implementing the necessary analysis is a feature request.

So now the relevant question is: which feature of C# would you like to cut in order to give the development team the budget to design, spec, implement, test, debug, ship and maintain forever a feature which statically finds a bug in a program where the developer is explicitly asking for static checking to be turned off? Keep in mind that the cost includes ensuring that no future feature of the language ever interferes with the compiler's ability to make this deduction; some of those costs are taxes that are paid by the design team in the future.

There are a small number of scenarios where an expression containing dynamic is statically analyzed; for example, there are some overload resolution problems involving static methods with dynamic arguments where the compiler can and does figure out that no matter what is provided at runtime, overload resolution is going to fail. But aside from those few cases, the language design team has historically judged that it's simply not good bang for buck to spend its limited budget on scenarios like the one you've identified.

OTHER TIPS

Since the input is dynamic, the compiler can't even determine if the result of your function is an int. It will attempt to cast the result to an int at the time the function is executed and fail if that can't be done. Now if you are asking why you would even be allowed to construct such code given the static type constraint has no way of being enforced - remember that dynamic isn't so much a type as a warning flag for "your normal static type rules don't apply here".

Check out the concept of "dynamic contagion" for more insight.

"The type is a static type, but an object of type dynamic bypasses static type checking."

If any part of your type is dynamic, the compiler must treat the whole thing as dynamic. So:

Func<dynamic, int> parseLength = <some func>  // is dynamic and type cannot be evaluated until runtime.

So the compiler allows this code:

DateTime wrongType = parseLength

This will compile and, as you expect, will produce a runtime error.

Dynamic typing is useful under certain circumstances. My personal experience of such value is accessing unmanaged code in COM components.

It's basically telling the compiler, "Trust me, this is going to work. =)" Or, "These are not the droids you're looking for"

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top