Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the rules the C# compiler uses to resolve types in a lambda expression?

Tags:

c#

With reference to Why can't an anonymous method be assigned to var?, I understand that the following is not supported in C#:

var func = (x,y) => Math.Log(x) + Math.Log(y);

However, I can create a method, Func of the form:

public static Func<T,T,T> Func<T>(Func<T,T,T> f) => f;

and then do:

var func = Func<double>((x,y) => Math.Log(x) + Math.Log(y));

that will compile just fine. However, for lambdas with different types for the parameters and return value, things get odd. For example, if I have a method:

public static Func<T1,T2,T3> Func<T1,T2,T3>(Func<T1,T2,T3> f) => f;

I can for example do:

var func = Func((double x, double y) => $"{x + y}");

and that too will compile. So the C# compiler seems to be able to infer the return type for a lambda. But, the following won't compile:

var func = Func((x,y) => Math.Log(x) + Math.Log(y));

as the compiler doesn't seem able to infer the types of x and y from the way they are used in the body.

So, my question: what are the definitive rules on type inference of lambda expressions; what will the compiler infer and what won't it?

like image 644
David Arno Avatar asked Dec 08 '25 14:12

David Arno


1 Answers

what are the definitive rules on type inference of lambda expressions;

The definitive rules are in the specification. If you want to look at the implementation, you can find it easily enough in the Roslyn sources; I commented it pretty heavily, anticipating that there would be questions. Note that in particular the comment starting around line 110 is relevant to your question; study this carefully if you want a deep understanding of how lambda type inference works.

https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs

Consider compiling the compiler yourself in debug mode; you can then use the Dump method at breakpoints to describe the state of the type inference engine as it goes. I used this to facilitate more rapid debugging, and when considering extensions to the algorithm. (Some of which are still in the code, commented out.)

what will the compiler infer and what won't it?

That is far too broad a question to answer definitively. But the basic action with respect to the examples in your question is:

  • Bounds on type parameters are inferred from ordinary arguments matched with formal parameter types.
  • Lambdas where all formal parameter types of the lambda are inferred or known have their return types inferred
  • The previous step is repeated until the algorithm fails to make progress or deduces a contradiction.

I recorded a video -- ten years ago now -- explaining all this step by step but apparently it is no longer on MSDN. I am vexed.

like image 58
Eric Lippert Avatar answered Dec 10 '25 02:12

Eric Lippert



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!