C# generics -- why do lambdas work, when simple methods don't? - c#

I'm having trouble understanding why the C# compiler can infer types for
Array.ConvertAll(new int[1], i => Convert.ToDouble(i));
but not for
Array.ConvertAll(new int[1], Convert.ToDouble);
when it would seem that the former would be a more complicated deduction than the latter.
Could someone please explain why this happens?

This issue is pretty well covered in this (archived) blog post: http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx
In summary as I understand it (should the link ever vanish); this was a conscious design decision in C# 3.0, in that it was not appropriate to perform type inference on Method Groups (your second example).
I guess quite a few folks didn't like that, so the issue was resolved for C# 4.0 (as of Visual Studio 2010);
"In C# 4.0, return type inference works on method group arguments when the method group can be associated unambiguously with a completely fixed set of argument types deduced from the delegate. Once the argument types associated with the method group are known, then overload resolution can determine unambiguously which method in the method group is the one associated with the delegate formal parameter; we can then make a return type inference from the specific method to the delegate return type."

Related

Infer nesting generic type parameter [duplicate]

This question already has answers here:
Why must I provide explicitly generic parameter types While the compiler should infer the type?
(3 answers)
Closed 9 years ago.
I've noticed that the C# compiler doesn't infer second generic parameter.
Example:
C++ template code: (yea I know that templates don't work like generics)
class Test {
public:
template <class T,class V>
T test(V v) {
//do something with v
return T();
}
};
int i = 0;
Test t = new Test();
double j = t.test<double>(i); //infers V as int
The templates (and generics) can't infer return type, so in C++ I give it the first template parameter, and the second template parameter is inferred from the variable type.
Now, same example in C#:
class Test {
public T test<T,V>(V v) where T: new() {
//do something with v
return new T();
}
};
int i = 0;
Test t = new Test();
double j = t.test<double>(i); //Error Using the generic method 'Test.test<T,V>(V)' requires '2' type arguments
But if i use 1 type, I don't have to explicitly specify the type:
class Test {
public V test<V>(V v) where V: new() {
return new V();
}
};
int i = 0;
Test t = new Test();
int j = t.test(i); //OK infers V as int.
So, why can't C# generics infer the second type (while in c++ templates it clearly can) ?
I'm sure it's designed that way (I doubt they the .Net team overlooked this), so why is it designed this way that I must explicitly specify both types?
Edit:
From the discussions we had in the answers so far, both languages support overloading by number of template parameters.
So again, why is C# designed this way ? What's different in the language implementation that doesn't allow to explicitly declare only one parameter ?
C# has been designed to be a slightly less brain-bending language than C++.
In particular, I don't think it's a great idea to compare C# generics to C++ templates for various reasons - they're fundamentally two really quite different approaches to accomplishing similar things in some situations. The C++ approach is certainly flexible in some ways - although it doesn't allow (as I understand it) templates which only exist in binary form, or new template specializations to be created at execution time. Basically the C++ templating approach doesn't sit well with the rest of how .NET fits together.
Now as for why you can't specify some type arguments and allow others to be inferred (which is a language decision rather than a platform decision; I'm sure it would be feasible as far as .NET itself is concerned) - again, I believe this is for the sake of simplicity. Choosing the exact right method and the right type arguments is already extremely complicated in C# - more complicated than most C# developers can get their heads round. It involves:
Potentially considering methods up the type hierarchy from the compile-time type of the target
Overloading by number of parameters
Overloading by the number of type parameters
The effect of named arguments
The effect of optional parameters
The effect of generic type parameter constraints on parameter types (not constraints specified by the target method, note)
Method group to delegate conversions
Anonymous function conversions
Type inference for type arguments
Dynamic typing
Generic covariance and contravariance
Personally, I think that's enough to get my head around, without allowing yet more possiblities via "M can still be a candidate if it has at least as many type parameters as specified type arguments". Would you also want named type arguments and optional type parameters? ;)
I've looked at overloading quite a lot, following the spec thoroughly etc. I've found areas which make the language designers scratch their heads and try to work out what the compiler should do. I've found areas which the compiler definitely gets wrong. I wouldn't want to add any more complexity here without a really good reason.
So yes, it's basically for the sake of simplicity, and sometimes that's a pain - but often you can work around it. For every potential feature, you need to consider:
The benefit of the feature to end developers
The cost of the feature to end developers in terms of time spent understanding it
The cost to the language designers in designing and specifying it thoroughly
The cost to the compiler writers in implementing it correctly
The cost to the test team in testing it thoroughly (in conjunction with everything else around overloading)
The cost to future potential features (if this one makes the language more complicated, that leaves less "potentially grokable" additional complexity for other features)
As Dan said, C# doesn't allow you to infer only some type parameters of a generic parameter set. This is likely to enable overloading based on the number of generic parameters (which C# allows, at least for generic classes).
However, you can specify parameters of a generic class, and infer parameters of a generic method within that class. But this workaround isn't always a good solution.
One thing that can help in some cases where one would want to specify some type parameters and have others inferred is to create a generic static class with the parameters one wants to specify, and then within that class have a generic static method with the parameters one wants to have inferred. For example, I have a method which, given a method which is convertable to an Action(T,U,V), along with a T, will generate an Action(U,V) that will call that delegate with the originally-specified T along with the U and V. The method would be invoked as (vb syntax):
NewAction = ActionOf(Of FooType, BarType).NewAction(AddressOf MyFunctionOfBozFooBar, someBoz)
The compiler can determine one of the generic type parameters using the type of someBoz, even though it needs to have the FooType and BarType parameters explicitly specified.

Strange C# compiler behavior when choosing overload that looks like a bug/missing feature

I have recently found an interesting behavior of C# compiler. Imagine an interface like this:
public interface ILogger
{
void Info(string operation, string details = null);
void Info(string operation, object details = null);
}
Now if we do
logger.Info("Create")
The compiler will complain that he does not know which overload to chose (Ambiguous invocation...). Seems logical, but when you try to do this:
logger.Info("Create", null)
It will suddenly have no troubles figuring out that null is a string. Moreover it seems that the behavior of finding the right overload has changed with time and I had found a bug in an old code that worked before and stopped working because compiler decided to use another overload.
So I am really wondering why does C# not generate the same error in the second case as it does in the first. Seems very logical to do this, but instead it tries and resolves it to random overload.
P.S. I don't think that it's good to provide such ambiguous interfaces and do not recommend that, but legacy is legacy and has to be maintained :)
There was a breaking change introduced in C# 6 that made the overload resolution better. Here it is with the list of features:
Improved overload resolution
There are a number of small improvements to overload resolution, which will likely result in more things just working the way you’d expect them to. The improvements all relate to “betterness” – the way the compiler decides which of two overloads is better for a given argument.
One place where you might notice this (or rather stop noticing a problem!) is when choosing between overloads taking nullable value types. Another is when passing method groups (as opposed to lambdas) to overloads expecting delegates. The details aren’t worth expanding on here – just wanted to let you know!
but instead it tries and resolves it to random overload.
No, C# doesn't pick overloads randomly, that case is the ambiguous call error. C# picks the better method. Refer to section 7.5.3.2 Better function member in the C# specs:
7.5.3.2 Better function member
Otherwise, if MP has more specific parameter types than MQ, then MP is better than MQ. Let {R1, R2, …, RN} and {S1, S2, …, SN} represent the uninstantiated and unexpanded parameter types of MP and MQ. MP’s parameter types are more specific than MQ’s if, for each parameter, RX is not less specific than SX, and, for at least one parameter, RX is more specific than SX:
Given that string is more specific than object and there is an implicit cast between null and string, then the mystery is solved.

Why isn't this inferred automatically?

Up until now, C# inferrence has always worked well for me. I have created a test example to simplify the case.
class Parent
{
public void InferrenceTesting<T>() where T : Parent
{
}
}
class Child : Parent
{
public void Test()
{
//this line gives me a compiler error : The type arguments for method 'Parent.InferrenceTesting<T>()' cannot be inferred from the usage. Try specifying the type arguments explicitly.
this.InferrenceTesting();
}
}
I have read quite a lot on inferrence, but I am clueless as of why this doesn't work.
Inference of generic method type arguments to the method type parameters proceeds by making inferences based on the relationships between the formal arguments and the formal parameters.
Your method has zero formal arguments and zero formal parameters, so no inferences are made.
Note that in particular inferences are never made from generic parameter constraints. Constraints are not part of the signature of a method and inference concerns itself with signatures. Rather, constraints are checked after type inference has succeeded. If you're expecting some sort of inference to be made from your where clause, your expectation is mistaken.
I have read quite a lot on inference, but I am clueless as of why this doesn't work.
You may wish to read my blog articles on type inference if this subject interests you. They may be more accurate than some of the other articles you've read on this subject; I occasionally see misinformation out there. From my current blog:
https://ericlippert.com/category/csharp/type-inference/
And my former Microsoft blog:
https://blogs.msdn.microsoft.com/ericlippert/tag/type-inference/
In particular, see
https://blogs.msdn.microsoft.com/ericlippert/2009/12/10/constraints-are-not-part-of-the-signature/
The comments to that blog are quite interesting. If you've ever wanted to see like a hundred people tell me that I'm wrong, the design is wrong, the implementation is wrong, well, that's the place to go.
There's nothing it can use to infer the type from. You've said that T has to be a type of Parent but since you're not passing a parameter of that type (which the compiler can use to infer the type) you'll have to explicitly name the type.
The compiler has no information to infer from - you need a parameter or some other information to tell the compiler what T should be in order to infer it.
I'm no expert in this, but I think there is nothing to infer from.
The simple fact that this method is declared in a Parent derivate has nothing to do with it.
You need an argument of type T for that method so that the compiler has something from which he can infere what should be used as T.
In your call, T does not need to be either Parent or Child. It can be anything as long as it inherits from Parent.

Generics can't infer second parameter? [duplicate]

This question already has answers here:
Why must I provide explicitly generic parameter types While the compiler should infer the type?
(3 answers)
Closed 9 years ago.
I've noticed that the C# compiler doesn't infer second generic parameter.
Example:
C++ template code: (yea I know that templates don't work like generics)
class Test {
public:
template <class T,class V>
T test(V v) {
//do something with v
return T();
}
};
int i = 0;
Test t = new Test();
double j = t.test<double>(i); //infers V as int
The templates (and generics) can't infer return type, so in C++ I give it the first template parameter, and the second template parameter is inferred from the variable type.
Now, same example in C#:
class Test {
public T test<T,V>(V v) where T: new() {
//do something with v
return new T();
}
};
int i = 0;
Test t = new Test();
double j = t.test<double>(i); //Error Using the generic method 'Test.test<T,V>(V)' requires '2' type arguments
But if i use 1 type, I don't have to explicitly specify the type:
class Test {
public V test<V>(V v) where V: new() {
return new V();
}
};
int i = 0;
Test t = new Test();
int j = t.test(i); //OK infers V as int.
So, why can't C# generics infer the second type (while in c++ templates it clearly can) ?
I'm sure it's designed that way (I doubt they the .Net team overlooked this), so why is it designed this way that I must explicitly specify both types?
Edit:
From the discussions we had in the answers so far, both languages support overloading by number of template parameters.
So again, why is C# designed this way ? What's different in the language implementation that doesn't allow to explicitly declare only one parameter ?
C# has been designed to be a slightly less brain-bending language than C++.
In particular, I don't think it's a great idea to compare C# generics to C++ templates for various reasons - they're fundamentally two really quite different approaches to accomplishing similar things in some situations. The C++ approach is certainly flexible in some ways - although it doesn't allow (as I understand it) templates which only exist in binary form, or new template specializations to be created at execution time. Basically the C++ templating approach doesn't sit well with the rest of how .NET fits together.
Now as for why you can't specify some type arguments and allow others to be inferred (which is a language decision rather than a platform decision; I'm sure it would be feasible as far as .NET itself is concerned) - again, I believe this is for the sake of simplicity. Choosing the exact right method and the right type arguments is already extremely complicated in C# - more complicated than most C# developers can get their heads round. It involves:
Potentially considering methods up the type hierarchy from the compile-time type of the target
Overloading by number of parameters
Overloading by the number of type parameters
The effect of named arguments
The effect of optional parameters
The effect of generic type parameter constraints on parameter types (not constraints specified by the target method, note)
Method group to delegate conversions
Anonymous function conversions
Type inference for type arguments
Dynamic typing
Generic covariance and contravariance
Personally, I think that's enough to get my head around, without allowing yet more possiblities via "M can still be a candidate if it has at least as many type parameters as specified type arguments". Would you also want named type arguments and optional type parameters? ;)
I've looked at overloading quite a lot, following the spec thoroughly etc. I've found areas which make the language designers scratch their heads and try to work out what the compiler should do. I've found areas which the compiler definitely gets wrong. I wouldn't want to add any more complexity here without a really good reason.
So yes, it's basically for the sake of simplicity, and sometimes that's a pain - but often you can work around it. For every potential feature, you need to consider:
The benefit of the feature to end developers
The cost of the feature to end developers in terms of time spent understanding it
The cost to the language designers in designing and specifying it thoroughly
The cost to the compiler writers in implementing it correctly
The cost to the test team in testing it thoroughly (in conjunction with everything else around overloading)
The cost to future potential features (if this one makes the language more complicated, that leaves less "potentially grokable" additional complexity for other features)
As Dan said, C# doesn't allow you to infer only some type parameters of a generic parameter set. This is likely to enable overloading based on the number of generic parameters (which C# allows, at least for generic classes).
However, you can specify parameters of a generic class, and infer parameters of a generic method within that class. But this workaround isn't always a good solution.
One thing that can help in some cases where one would want to specify some type parameters and have others inferred is to create a generic static class with the parameters one wants to specify, and then within that class have a generic static method with the parameters one wants to have inferred. For example, I have a method which, given a method which is convertable to an Action(T,U,V), along with a T, will generate an Action(U,V) that will call that delegate with the originally-specified T along with the U and V. The method would be invoked as (vb syntax):
NewAction = ActionOf(Of FooType, BarType).NewAction(AddressOf MyFunctionOfBozFooBar, someBoz)
The compiler can determine one of the generic type parameters using the type of someBoz, even though it needs to have the FooType and BarType parameters explicitly specified.

Limitations of the dynamic type in C#

Could you give me some reasons for limitations of the dynamic type in C#? I read about them in "Pro C# 2010 and the .NET 4 platform". Here is an excerpt (if quoting books is illegal here, tell me and I will remove the excerpt):
While a great many things can be
defined using the dynamic keyword,
there are some limitations regarding
its usage. While they are not show
stoppers, do know that a dynamic data
item cannot make use of lambda
expressions or C# anonymous methods
when calling a method. For example,
the following code will always result
in errors, even if the target method
does indeed take a delegate parameter
which takes a string value and returns
void.
dynamic a = GetDynamicObject();
// Error! Methods on dynamic data can’t use lambdas!
a.Method(arg => Console.WriteLine(arg));
To circumvent this restriction, you
will need to work with the underlying
delegate directly, using the
techniques described in Chapter 11
(anonymous methods and lambda
expressions, etc). Another limitation
is that a dynamic point of data cannot
understand any extension methods (see
Chapter 12). Unfortunately, this would
also include any of the extension
methods which come from the LINQ APIs.
Therefore, a variable declared with
the dynamic keyword has very limited
use within LINQ to Objects and other
LINQ technologies:
dynamic a = GetDynamicObject();
// Error! Dynamic data can’t find the Select() extension method!
var data = from d in a select d;
Thanks in advance.
Tomas's conjectures are pretty good. His reasoning on extension methods is spot on. Basically, to make extension methods work we need the call site to at runtime somehow know what using directives were in force at compile time. We simply did not have enough time or budget to develop a system whereby this information could be persisted into the call site.
For lambdas, the situation is actually more complex than the simple problem of determining whether the lambda is going to expression tree or delegate. Consider the following:
d.M(123)
where d is an expression of type dynamic. *What object should get passed at runtime as the argument to the call site "M"? Clearly we box 123 and pass that. Then the overload resolution algorithm in the runtime binder looks at the runtime type of d and the compile-time type of the int 123 and works with that.
Now what if it was
d.M(x=>x.Foo())
Now what object should we pass as the argument? We have no way to represent "lambda method of one variable that calls an unknown function called Foo on whatever the type of x turns out to be".
Suppose we wanted to implement this feature: what would we have to implement? First, we'd need a way to represent an unbound lambda. Expression trees are by design only for representing lambdas where all types and methods are known. We'd need to invent a new kind of "untyped" expression tree. And then we'd need to implement all of the rules for lambda binding in the runtime binder.
Consider that last point. Lambdas can contain statements. Implementing this feature requires that the runtime binder contain the entire semantic analyzer for every possible statement in C#.
That was orders of magnitude out of our budget. We'd still be working on C# 4 today if we'd wanted to implement that feature.
Unfortunately this means that LINQ doesn't work very well with dynamic, because LINQ of course uses untyped lambdas all over the place. Hopefully in some hypothetical future version of C# we will have a more fully-featured runtime binder and the ability to do homoiconic representations of unbound lambdas. But I wouldn't hold my breath waiting if I were you.
UPDATE: A comment asks for clarification on the point about the semantic analyzer.
Consider the following overloads:
class C {
public void M(Func<IDisposable, int> f) { ... }
public void M(Func<int, int> f) { ... }
...
}
and a call
d.M(x=> { using(x) { return 123; } });
Suppose d is of compile time type dynamic and runtime type C. What must the runtime binder do?
The runtime binder must determine at runtime whether the expression x=>{...} is convertible to each of the delegate types in each of the overloads of M.
In order to do that, the runtime binder must be able to determine that the second overload is not applicable. If it were applicable then you could have an int as the argument to a using statement, but the argument to a using statement must be disposable. That means that the runtime binder must know all the rules for the using statement and be able to correctly report whether any possible use of the using statement is legal or illegal.
Clearly that is not restricted to the using statement. The runtime binder must know all the rules for all of C# in order to determine whether a given statement lambda is convertible to a given delegate type.
We did not have time to write a runtime binder that was essentially an entire new C# compiler that generates DLR trees rather than IL. By not allowing lambdas we only have to write a runtime binder that knows how to bind method calls, arithmetic expressions and a few other simple kinds of call sites. Allowing lambdas makes the problem of runtime binding on the order of dozens or hundreds of times more expensive to implement, test and maintain.
Lambdas: I think that one reason for not supporting lambdas as parameters to dynamic objects is that the compiler wouldn't know whether to compile the lambda as a delegate or as an expression tree.
When you use a lambda, the compiler decides based on the type of the target parameter or variable. When it is Func<...> (or other delegate) it compiles the lambda as an executable delegate. When the target is Expression<...> it compiles lambda into an expression tree.
Now, when you have a dynamic type, you don't know whether the parameter is delegate or expression, so the compiler cannot decide what to do!
Extension methods: I think that the reason here is that finding extension methods at runtime would be quite difficult (and perhaps also inefficient). First of all, the runtime would need to know what namespaces were referenced using using. Then it would need to search all classes in all loaded assemblies, filter those that are accessible (by namespace) and then search those for extension methods...
Eric (and Tomas) says it well, but here is how I think of it.
This C# statement
a.Method(arg => Console.WriteLine(arg));
has no meaning without a lot of context. Lambda expressions themselves have no types, rather they are convertible to delegate (or Expression) types. So the only way to gather the meaning is to provide some context which forces the lambda to be converted to a specific delegate type. That context is typically (as in this example) overload resolution; given the type of a, and the available overloads Method on that type (including extension members), we can possibly place some context that gives the lambda meaning.
Without that context to produce the meaning, you end up having to bundle up all kinds of information about the lambda in the hopes of somehow binding the unknowns at runtime. (What IL could you possibly generate?)
In vast contrast, one you put a specific delegate type there,
a.Method(new Action<int>(arg => Console.WriteLine(arg)));
Kazam! Things just got easy. No matter what code is inside the lambda, we now know exactly what type it has, which means we can compile IL just as we would any method body (we now know, for example, which of the many overloads of Console.WriteLine we're calling). And that code has one specific type (Action<int>), which means it is easy for the runtime binder to see if a has a Method that takes that type of argument.
In C#, a naked lambda is almost meaningless. C# lambdas need static context to give them meaning and rule out ambiguities that arise from many possible coercisons and overloads. A typical program provides this context with ease, but the dynamic case lacks this important context.

Categories