27

I read that C# lambdas can be imlicitly converted to Action or Func , but lambda cannot be executed directly Define a lambda function and execute it immediately For example :

int n = (()=>5)(); //doesn't work
int n = ((Func<int>)(()=>5))(); //works

So what is the actual type of lambda and why it cannot be directly called? Is it because C# type system is "weaker" than Haskell or Scala one?

Community
  • 1
  • 1
ig-melnyk
  • 2,769
  • 2
  • 25
  • 35
  • 2
    The answer in the linked question is valid for your question. C# compiler needs to know context, which is either assignment or casting. In the first sample you do neither – Leri Jan 06 '15 at 09:43
  • The type system is not related to this. `Dim n = Function() 5` works just fine in VB.NET, and it's similar in F#, and they have the same underlying type system. This is just an issue with C#. – Mauricio Scheffer Jan 06 '15 at 23:17
  • @MauricioScheffer no F# and C# doesn't have the same "type system" . Why? Because 5.0+5 is incorrect in F#, but is still correct in C#. – ig-melnyk Jan 06 '15 at 23:32
  • @ig-melnyk that's a feature of the language, not of the type system. – Mauricio Scheffer Jan 07 '15 at 00:13
  • @MauricioScheffer and this "feature" is called "type system" - how types "work" together. – ig-melnyk Jan 07 '15 at 00:48
  • @ig-melnyk language != type system , but whatever, honestly I'm not interesting in discussing this. – Mauricio Scheffer Jan 07 '15 at 00:54

2 Answers2

29

A lambda expression doesn't have a type. It cannot, because any type in the .NET world that it could have, would also hard-code the type of the lambda's parameters and result. Now consider:

x => x + 1

What type could x have? What type will the result be? There isn't any single answer, and the lambda expression can indeed be converted to Func<int, int>, Func<double, double>, and many other delegate types with different parameters. Giving a lambda expression a type would disallow such expressions. C# did want to allow such expressions, so was designed not to give such expressions any type.

  • 1
    well explained, if a code example be given, i am instersted – Ehsan Sajjad Jan 06 '15 at 09:48
  • 2
    I'm not sure what sort of code example you have in mind, all I can think to add is examples of delegate types the expression could be converted to, which I've now included in the answer. –  Jan 06 '15 at 09:51
  • It makes sense. I have just tested this in F# and Haskell. In F# in works only for "int" - the reason is that F# doesn't use implicit conversions. In the case of C# - compiler really can't "know" the type, so you are right. – ig-melnyk Jan 06 '15 at 09:59
  • @ig-melnyk What about `x => x + x`? This would not use any conversion from `int` to `double`. –  Jan 06 '15 at 10:09
  • I thought it can create in the compile-time different functions for example : (x=>x+x)(5) : Func because we called this function with an int argument .By the way, I accepted your answer because it really answers my question – ig-melnyk Jan 06 '15 at 10:13
  • @ig-melnyk Even if that did implicitly convert the lambda expression to `Func` in an extended C#, wouldn't the lambda expression itself still not have any type? –  Jan 06 '15 at 10:19
  • 2
    As a further example, in `static List AppendOnes(List li) { return li.ConvertAll(x => x + 1); }` the arrow becomes an instance of `System.Converter`. Historically, the generic delegate `Converter<,>` existed before the BCL had "funcs", i.e. the type family `Func<>`, `Func<,>`, `Func<,,>`, etc. – Jeppe Stig Nielsen Jan 06 '15 at 13:21
  • My IDE (ReSomething ;-) ) mostly uses `Action` in the simplest lambda case. – Xan-Kun Clark-Davis Oct 04 '22 at 00:43
9

This is because () => 5 can be compatible with various delegate types (e.g. you may have a custom delegate that takes nothing and returns int). And in order to create a delegate, compiler has to know the exact type. It can't just pick a random type that suits your needs. So that's why unless you cast it to an actual delegate type, you can't Invoke it.

In cases like where a method expects a delegate, that conversion is implicitly done by the compiler:

void Foo(Func<int> func) {  }

Foo(() => 5); 

And it is also important to know that delegates are actually classes behind the scenes. And each time you create a delegate instance, compiler creates an instance of that class. So either way you have to specify a type so the compiler will know which type to use.

Selman Genç
  • 100,147
  • 13
  • 119
  • 184