Compiler should not declare var as dynamic if it is the result of a function call with typed return value #2136
Replies: 18 comments
-
Why would anyone design such a thing? The example gives me no idea why the var gets declared dynamic. |
Beta Was this translation helpful? Give feedback.
-
@Korporal Any expression that contains a |
Beta Was this translation helpful? Give feedback.
-
Won't this be a breaking change: class A {}
class B : A
{
public int F = 42;
}
...
A ToA(dynamic a) => a;
...
var X = ToA((dynamic)new B()).F; |
Beta Was this translation helpful? Give feedback.
-
@HaloFour |
Beta Was this translation helpful? Give feedback.
-
@Korporal
And it's not resolved or invoked until runtime, so the static return type of the method is largely irrelevant. The compiler will do some very basic type checking for you, which is why it is a compiler error if the method doesn't exist in scope at all. But beyond that the compiler defers all evaluation, which can be abundantly clear when the situation is not so trivial, such as when there are overloads involved. That's the entire point of |
Beta Was this translation helpful? Give feedback.
-
@HaloFour - I can understand what you say, but to disregard the specified method's concrete return type just because an argument to that method is dynamic feels so counter intuitive, these counter intuitive things end up making code harder to reason about especially when perusing production code in an urgent operational setting, this very issue thread begins by pointing out expected behavior, why it wasn't done this way initially escapes me. I think C# is beginning to become overly complex and idiosyncratic. |
Beta Was this translation helpful? Give feedback.
-
@Korporal
The rule is very simple: any expression that contains a If the compiler sometimes returned |
Beta Was this translation helpful? Give feedback.
-
So does gafter's OP not imply that the current behavior is undesirable and must change? This also implies that it is not possible to write a method that returns a string if any arg to the method is dynamic, one must do all the fiddly stuff outside of the method, that is caller. |
Beta Was this translation helpful? Give feedback.
-
Okay, I didn't realize this is a language specification. Also seems rather counterintuitive to me. If a method that has dynamic parameters is automatically evaluated as dynamic expression then why isn't the return type forced to be dynamic? The fact that one is able to specify a return type suggest that the return type is somehow static although it isn't. Another thing that's confusing me right now is why a local func behaves differently from a regular method in terms of dynamic return type? Here the return type seems to be taken into consideration. I didn't mean to strongly suggest a change in language specification but to me this behaviour feels rather odd. |
Beta Was this translation helpful? Give feedback.
-
I rarely use private static string ToStringFromDynamic2(dynamic dynamicString)
{
return (string)(dynamicString?.ToString() as string);
}
Maybe the "solution" to this is to annotate the method or introduce some operator that forces the caller to not treat the method type as dynamic. That way existing behavior remains but there's a way to get this cleaner behavior? private static string ToStringFromDynamic(dynamic dynamicString)
{
force return "Hello";
} or private static (string) ToStringFromDynamic(dynamic dynamicString)
{
return "Hello";
} Or whatever, but this is getting messy! |
Beta Was this translation helpful? Give feedback.
-
It's rather ugly that method 1 works whereas 2 doesn't: class Program
{
static void Main(string[] args)
{
dynamic y = string.Empty;
var z = (string)ToStringFromDynamic1(y);
var w = ToStringFromDynamic2(y);
}
private static string ToStringFromDynamic1(dynamic dynamicString)
{
return dynamicString?.ToString() as string;
}
private static string ToStringFromDynamic2(dynamic dynamicString)
{
return (string)(dynamicString?.ToString() as string);
}
} Especially when all the code is in the same compilation unit. I feel the C# language is increasingly creating a growing burden on the things a developer has to memorize, this is why counter intuitive language enhancements can degrade a language over time. |
Beta Was this translation helpful? Give feedback.
-
@Korporal
It's the caller that makes the decision to treat the return type as And you have to remember that dynamic runtime binding also defers overload resolution, which is why the following compiles and works: public class C {
public string M(int x) => "Hello";
public int M(string x) => 123;
public void M(dynamic d) {
// what is z here? You can't know at compile-time
var z = M(d);
}
} |
Beta Was this translation helpful? Give feedback.
-
That's a good example so thanks. So is there scope for an optimization then? In cases where there is no overload and therefore no compile time ambiguity the caller simply accepts the declared method return type as the type? Perhaps that's what happens in gafta's second example with a local method. |
Beta Was this translation helpful? Give feedback.
-
@Korporal
I believe that's what the compiler is doing with local functions, as they're entirely contained and overloading is not supported. I imagine that it might be possible to optimize dynamic in very specific circumstances, such as when the method returns using System;
public class Person { }
public class Student : Person { }
public class C {
public Person GetPerson(string s) => new Student();
public void M(Person p) => Console.WriteLine("Person!");
public void M(Student s) => Console.WriteLine("Student!");
public void N(dynamic d) {
var person = GetPerson(d);
M(person);
}
} If |
Beta Was this translation helpful? Give feedback.
-
Maybe the solution could be to not defer overload resolution if there is an overload that explicitly expects a dynamic parameter? Example:
Would be more intuitive for me if z would be 1.1 since a specific dynamic overload exists |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
What about adding a warning in the new update to indicate return type should be dynamic as well and static types are ignored in that case. Like when you have async method without await statement. |
Beta Was this translation helpful? Give feedback.
-
They are not ignored if you have a class C
{
int M(dynamic dynamicParameter) => 42;
public void Main()
{
object nonDynamicArgument = new object();
dynamic dynamicArgument = o;
var x = M(nonDynamicArgument); // x is int
var y = M(dynamicArgument); // y is dynamic
}
} There's nothing wrong with the method |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
@rangp commented on Fri Jan 11 2019
*VS 2017 C# Tool 2.10.0-beta2:
Repro Steps:
Function has return type
string
:Usage like this:
Expected Behavior:
x is declared as string because of the function return type.
Actual Behavior:
x is also declared as dynamic.
Interestingly if I declare
ToStringFromDynamic
as local func:it works as expected.
@gafter commented on Fri Jan 11 2019
The language specification requires the current behavior, so I'm moving this to csharplang.
Beta Was this translation helpful? Give feedback.
All reactions