By Marlon


2011-02-11 04:17:03 8 Comments

I have the following code:

Func<string, bool> comparer = delegate(string value) {
    return value != "0";
};

However, the following does not compile:

var comparer = delegate(string value) {
    return value != "0";
};

Why can't the compiler figure out it is a Func<string, bool>? It takes one string parameter, and returns a boolean. Instead, it gives me the error:

Cannot assign anonymous method to an implicitly-typed local variable.

I have one guess and that is if the var version compiled, it would lack consistency if I had the following:

var comparer = delegate(string arg1, string arg2, string arg3, string arg4, string arg5) {
    return false;
};

The above wouldn't make sense since Func<> allows only up to 4 arguments (in .NET 3.5, which is what I am using). Perhaps someone could clarify the problem. Thanks.

7 comments

@Ambrose Leung 2018-11-08 15:55:37

My post doesn't answer the actual question, but it does answer the underlying question of :

"How do I avoid having to type out some fugly type like Func<string, string, int, CustomInputType, bool, ReturnType>?" [1]

Being the lazy/hacky programmer that I am, I experimented with using Func<dynamic, object> - which takes a single input parameter and returns an object.

For multiple arguments, you can use it like so:

dynamic myParams = new ExpandoObject();
myParams.arg0 = "whatever";
myParams.arg1 = 3;
Func<dynamic, object> y = (dynObj) =>
{
    return dynObj.arg0.ToUpper() + (dynObj.arg1 * 45); //screw type casting, amirite?
};
Console.WriteLine(y(myParams));

Tip: You can use Action<dynamic> if you don't need to return an object.

Yeah I know it probably goes against your programming principles, but this makes sense to me and probably some Python coders.

I'm pretty novice at delegates... just wanted to share what I learned.


[1] This assumes that you aren't calling a method that requires a predefined Func as a parameter, in which case, you'll have to type that fugly string :/

@mmm 2013-12-19 08:07:55

How is about that?

var item = new
    {
        toolisn = 100,
        LangId = "ENG",
        toolPath = (Func<int, string, string>) delegate(int toolisn, string LangId)
        {
              var path = "/Content/Tool_" + toolisn + "_" + LangId + "/story.html";
              return File.Exists(Server.MapPath(path)) ? "<a style=\"vertical-align:super\" href=\"" + path + "\" target=\"_blank\">execute example</a> " : "";
        }
};

string result = item.toolPath(item.toolisn, item.LangId);

@Eric Lippert 2011-02-11 06:58:17

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:

Func<A, R> WorkItOut<A, R>(Func<A, R> f) { return f; }
...
var xAnon = WorkItOut((int y)=>new { Y = y });

and now method type inference works out what the func type is.

@The Scrum Meister 2011-02-11 07:05:07

+1 Great answer. With everyone calling your name we knew you'd show up.

@Matt Greer 2011-02-11 16:13:23

When are you going to compile your SO answers into a book? I'd buy it :)

@Adam Rackis 2011-02-17 20:54:18

I second the proposal for an Eric Lippert book of SO answers. Suggested title: "Reflections From The Stack"

@Mehrdad 2011-08-01 11:24:39

@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. :)

@Jonathan Dickinson 2011-11-08 08:12:55

What would probably be something interesting to see would be dynamic foo = x => x + y - you could probably turn this into a trampoline that returns runtime compiled delegates - although it would probably only be interesting and nothing else.

@Raphaël Saint-Pierre 2012-05-02 19:31:38

That means that we still have to define the WorkItOut<> generic as many times as we need different numbers of parameters, right ?

@turbanoff 2012-05-31 06:19:52

@ Raphaël Saint-Pierre: Right. C# don't support variadic template.

@Rune FS 2013-05-02 11:02:00

"...Or do we? Is the return int? long? short? byte?" int, long, short or byte seems more appropriate than the nullable alternatives :p (yeah yeah I know those are question marks and not part of the type)

@nawfal 2013-05-29 12:26:33

//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? // There are a few scenarios in C# where compiler throws ambiguity error (which means C# is not oblivious to making things easier only at times). Well if this feature doesn't make your benefit to cost ratio, then its a fair point..

@Eric Lippert 2013-05-29 13:49:49

@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.

@michael 2016-01-05 19:14:34

@Eric: If we assume that Func is the most common intent when assigning a lambda to a 'var' local, then it seems relatively easy for the C# compiler to essentially employ the behavior of your "WorkItOut" template in variadic form, since it works today in the current C# compiler. When passed to WorkItOut, each of the problematic examples you list produces the error "type arguments cannot be inferred from usage" except the last one (+=), which returns the resulting sum. This all seems quite reasonable, and I will be using my own "variadic" form of WorkItOut (multiple overloads) in the meantime.

@ATD 2016-05-11 15:53:49

var x2 = (int y) =>123; Why would this not work for a function when it works for standard variables such as: var x2 = 123; ?

@Eric Lippert 2016-05-11 16:06:59

@ATD: This answer answers that question: sure, the feature could be made to work for simple cases. That does not make the compiler developer's job easier. It makes it harder because now a "simple case detector" must be designed, specified, written, tested and documented. All that work takes away effort from features that actually would make a difference to developers' lives.

@AbstractDissonance 2017-06-17 14:14:46

But it should for for straightforward no param delegates () => { } ==> void delegate().After all, it is just an Action which is longer than var.

@Eric Lippert 2017-06-17 14:44:07

@AbstractDissonance: See my previous comment.

@AbstractDissonance 2017-06-17 18:25:13

@EricLippert That isn't an answer, that is a cop out. If you want to use that logic, you can use it to justify not having anything. Sorry, it's true... even though you will try to squirm out of the truth.

@Eric Lippert 2017-06-17 18:28:20

@abstractdissonance I assure you it is an answer. If its an answer you don't like then why not post an answer that you do like? That way I and everyone else can benefit from your insights on a question that plainly you care about.

@Eric Lippert 2017-06-17 18:41:54

@abstractdissonance I note also that the compiler is open source. If you care about this feature then you can donate the necessary time and effort to make it happen. I encourage you to submit a pull request.

@Eric Lippert 2017-06-18 00:27:19

@AbstractDissonance: Finally, your general claim is that I can use the logic "features have costs and benefits, and we try to implement only those features that give good benefits for reasonable costs" to justify not doing any feature. That is 100% correct. I do use that logic to not justify doing any feature whose costs exceed its benefits. There's no truth to "squirm out of" there; I have said dozens -- hundreds? -- of times on this site that features have costs and must be justified by their benefits. I not only embrace that truth, I state it emphatically over and over again!

@AbstractDissonance 2017-06-18 10:48:29

@EricLippert But that is BS. You have been brainwashed by the machine. At what cost? Who's cost? How are you measuring this so called "cost"? Are you the god given authority of what is cost and what is not? (You may claim to be, but it doesn't make it so). Since you can't measure this so called cost you claim exists, it is fictitious. Sure, you can measure it in the cost of bytes(file sizes), the cost of time put in(seconds), or the cost of money(which is just as made up), but it means nothing. What about the cost of lives? Or the cost of hopes and dreams?

@AbstractDissonance 2017-06-18 10:49:27

What you are really saying is simply: "It's not worth our time, we have better things WE want to do"... and that is not a logical argument but simply an emphatic choice. At least be honest with yourself instead of trying to justify your choice with logic.

@Eric Lippert 2017-06-18 14:01:15

@AbstractDissonance: We measured the cost in terms of the limited resources: developers and time. This responsibility was not granted by god; it was imposed by the vice president of the developer division. The notion that somehow the C# team could ignore a budget process is a strange one. I assure you, tradeoffs were and still are made by the careful, thoughtful consideration of experts who had the C# communities expressed wishes, the strategic mission for Microsoft, and their own excellent taste in design in mind.

@AbstractDissonance 2017-06-18 17:05:53

Ok, then we agree. They are made up rules to be congruent with other made up rules. I will have to disagree though about Microsoft. Microsoft does not have excellent taste in design(many windows products are a prime example). If we are specifically talking about C#'s design, then I would agree in relatively terms as it is a well designed language as compared to most(Although the IL representation and performance can be issues at times).

@nybbler 2011-02-11 04:55:54

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

  1. 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.
  2. The var keyword instructs the compiler to infer the type of the variable from the expression on the right side of the initialization statement.
  3. 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.

MSDN Reference: Implicitly Typed Local Variables

Considering the following regarding Anonymous Methods:

  1. Anonymous methods enable you to omit the parameter list.

MSDN Reference: Anonymous Methods

I would suspect that since the anonymous method may actually have different method signatures, the compiler is unable to properly infer what the most appropriate type to assign would be.

@Brian Rasmussen 2011-02-11 04:40:24

Eric Lippert has an old post about it where he says

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.

@Anthony Pegram 2011-02-11 04:49:48

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.

@Brian Rasmussen 2011-02-11 06:30:19

@Anthony: Thanks for the update.

@itowlson 2011-02-11 04:35:03

Only Eric Lippert knows for sure, but I think it's because the signature of the delegate type doesn't uniquely determine the type.

Consider your example:

var comparer = delegate(string value) { return value != "0"; };

Here are two possible inferences for what the var should be:

Predicate<string> comparer  = delegate(string value) { return value != "0"; };  // okay
Func<string, bool> comparer = delegate(string value) { return value != "0"; };  // also okay

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.

@Anthony Pegram 2011-02-11 04:47:36

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.

@Eric Lippert 2011-02-11 06:45:13

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.

@itowlson 2011-02-23 23:33:04

For anyone interested, I wrote up a bit more about this and how the C# and F# approaches contrast at mindscapehq.com/blog/index.php/2011/02/23/…

@Weipeng L 2018-07-25 17:29:39

why can't the compiler just fabricate a new unique type like C++ does for its lambda function

@Stephen Cleary 2011-02-11 04:34:44

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.

Related Questions

Sponsored Content

20 Answered Questions

[SOLVED] Create Generic method constraining T to an Enum

4 Answered Questions

[SOLVED] How to mark a method as obsolete or deprecated?

  • 2009-11-18 21:53:38
  • Chris Ballance
  • 228009 View
  • 900 Score
  • 4 Answer
  • Tags:   c# .net versioning

9 Answered Questions

[SOLVED] Why would you use Expression<Func<T>> rather than Func<T>?

10 Answered Questions

[SOLVED] Pass Method as Parameter using C#

11 Answered Questions

[SOLVED] Unsubscribe anonymous method in C#

19 Answered Questions

[SOLVED] Why is Dictionary preferred over Hashtable in C#?

12 Answered Questions

[SOLVED] Why is it important to override GetHashCode when Equals method is overridden?

  • 2008-12-16 13:41:18
  • David Basarab
  • 337673 View
  • 1321 Score
  • 12 Answer
  • Tags:   c# overriding hashcode

25 Answered Questions

[SOLVED] Why not inherit from List<T>?

4 Answered Questions

[SOLVED] Guid == null should not be allowed by the compiler

  • 2010-02-01 15:41:45
  • Luis Filipe
  • 12623 View
  • 46 Score
  • 4 Answer
  • Tags:   c# .net .net-3.5 guid

26 Answered Questions

[SOLVED] Why are Python lambdas useful?

Sponsored Content