6 Answers
6

Others have already pointed out that there are infinitely many possible delegate types that you could have meant; what is so special about Func that it deserves to be the default instead of Predicate or Action or any other possibility? And, for lambdas, why is it obvious that the intention is to choose the delegate form, rather than the expression tree form?

But we could say that Func is special, and that the inferred type of a lambda or anonymous method is Func of something. We'd still have all kinds of problems. What types would you like to be inferred for the following cases?

var x1 = (ref int y)=>123;

There is no Func<T> type that takes a ref anything.

var x2 = y=>123;

We don't know the type of the formal parameter, though we do know the return. (Or do we? Is the return int? long? short? byte?)

var x3 = (int y)=>null;

We don't know the return type, but it can't be void. The return type could be any reference type or any nullable value type.

var x4 = (int y)=>{ throw new Exception(); }

Again, we don't know the return type, and this time it can be void.

var x5 = (int y)=> q += y;

Is that intended to be a void-returning statement lambda or something that returns the value that was assigned to q? Both are legal; which should we choose?

Now, you might say, well, just don't support any of those features. Just support "normal" cases where the types can be worked out. That doesn't help. How does that make my life easier? If the feature works sometimes and fails sometimes then I still have to write the code to detect all of those failure situations and give a meaningful error message for each. We still have to specify all that behaviour, document it, write tests for it, and so on. This is a very expensive feature that saves the user maybe half a dozen keystrokes. We have better ways to add value to the language than spending a lot of time writing test cases for a feature that doesn't work half the time and doesn't provide hardly any benefit in cases where it does work.

The situation where it is actually useful is:

var xAnon = (int y)=>new { Y = y };

because there is no "speakable" type for that thing. But we have this problem all the time, and we just use method type inference to deduce the type:

+1 Great answer. With everyone calling your name we knew you'd show up.
–
The Scrum MeisterFeb 11 '11 at 7:05

24

When are you going to compile your SO answers into a book? I'd buy it :)
–
Matt GreerFeb 11 '11 at 16:13

10

I second the proposal for an Eric Lippert book of SO answers. Suggested title: "Reflections From The Stack"
–
Adam RackisFeb 17 '11 at 20:54

10

@Eric: Good answer, but it's slightly misleading to illustrate this as something that's not possible, as this actually works completely fine in D. It's just that you guys didn't choose to give delegate literals their own type, and instead made them depend on their contexts... so IMHO the answer should be "because that's how we made it" more than anything else. :)
–
MehrdadAug 1 '11 at 11:24

1

@nawfal: You're missing my point. Writing that ambiguity checker is also work. The hardest part of writing the overload resolution algorithm in C# is not writing it to get the correct cases working. The code that works out what error to give when the code is wrong is longer and more complicated than the code that works out the correct case. Ambiguity checkers are very difficult to get right because the code is ambiguous.
–
Eric LippertMay 29 '13 at 13:49

Which one should the compiler infer? There's no good reason to choose one or the other. And although a Predicate<T> is functionally equivalent to a Func<T, bool>, they are still different types at the level of the .NET type system. The compiler therefore cannot unambiguously resolve the delegate type, and must fail the type inference.

I'm sure quite a few other people at Microsoft also know for sure. ;) But yes, you allude to a chief reason, the compile time type cannot be determined because there is none. Section 8.5.1 of the language specification specifically highlights this reason for disallowing anonymous functions from being used in implicitly typed variable declarations.
–
Anthony PegramFeb 11 '11 at 4:47

Yep. And even worse, for lambdas we don't even know if it is going to a delegate type; it might be an expression tree.
–
Eric LippertFeb 11 '11 at 6:45

And in fact the C# 2.0 specification
calls this out. Method group
expressions and anonymous method
expressions are typeless expressions
in C# 2.0, and lambda expressions join
them in C# 3.0. Therefore it is
illegal for them to appear "naked" on
the right hand side of an implicit
declaration.

And this is underscored by section 8.5.1 of the language specification. "The initializer expression must have a compile-time type" in order to be used for a implicitly typed local variable.
–
Anthony PegramFeb 11 '11 at 4:49

Different delegates are considered different types. e.g., Action is different than MethodInvoker, and an instance of Action can't be assigned to a variable of type MethodInvoker.

So, given an anonymous delegate (or lambda) like () => {}, is it an Action or a MethodInvoker? The compiler can't tell.

Similarly, if I declare a delegate type taking a string argument and returning a bool, how would the compiler know you really wanted a Func<string, bool> instead of my delegate type? It can't infer the delegate type.

The following points are from the MSDN regarding Implicitly Typed Local Variables:

var can only be used when a local variable is declared and initialized in the same statement; the variable cannot be initialized to null, or to a method group or an anonymous function.

The var keyword instructs the compiler to infer the type of the variable from the expression on the right side of the initialization statement.

It is important to understand that the var keyword does not mean "variant" and does not indicate that the variable is loosely typed, or late-bound. It just means that the compiler determines and assigns the most appropriate type.