Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why don't anonymous delegates/lambdas infer types on out/ref parameters?

Several C# questions on StackOverflow ask how to make anonymous delegates/lambdas with out or ref parameters. See, for example:

  • Calling a method with ref or out parameters from an anonymous method
  • Write a lambda or anonymous function that accepts an out parameter

To do so, you just need to specify the type of the parameter, as in:

public void delegate D(out T p);
// ...
D a = (out T t) => { ... };      // Lambda syntax.
D b = delegate(out T t) { ... }; // Anonymous delegate syntax.

What I'm curious about is why the type is explicitly required. Is there a particular reason that this is the case? That is, from a compiler/language standpoint, why isn't the following allowed?

D a = (out t) => { ... };      // Lambda syntax -- implicit typing.
D b = delegate(out t) { ... }; // Anonymous delegate syntax -- implicit typing.

or even better, just:

D a = (t) => { ... };      // Lambda syntax -- implicit typing and ref|out-ness.
D b = delegate(t) { ... }; // Anonymous delegate syntax -- implicit typing and ref|out-ness.
like image 389
John Feminella Avatar asked Jan 02 '10 04:01

John Feminella


People also ask

Can you use ref and out parameters in lambda expression if declared outside?

In lambda expressions, you can't use the ref or out parameters.

What is lambda expression and delegate?

Lambda expression is an anonymous method that you can use to create delegates or expression tree types. Microsoft introduced Lambda Expression in C# 3.0 sometime in 2007. Most of the time, anonymous methods are confused with lambda expression by many developers.

What are anonymous functions in C#?

Anonymous methods provide a technique to pass a code block as a delegate parameter. Anonymous methods are the methods without a name, just the body. You need not specify the return type in an anonymous method; it is inferred from the return statement inside the method body.


1 Answers

Interesting question.

First, consider the difference between anonymous methods and lambdas. From the compiler writer's perspective, the most important difference is that lambdas can require the compiler to infer the type of the parameters from the target to which the lambda is being assigned; C# 2 anonymous methods do not have this feature. This feature seems like a small difference but in fact it has major ramifications on the implementation of the compiler. See my blog series on this topic for some thoughts on why that is:

http://blogs.msdn.com/ericlippert/archive/2007/01/10/lambda-expressions-vs-anonymous-methods-part-one.aspx

So now let's come to your actual question: why can we not infer outness/refness from the target type to the parameters of the lambda. That is, if we have delegate void D(out int x) then surely D d = x=> { x = 10; } could infer that x is "out int".

There's no technical reason I'm aware of why we could not do that. Internally in the compiler the out/ref types are represented as types like any other.

However, features do not get done just because they can be done; they get done because there's a compelling reason to do so. For lambdas, the compelling reason to do type inference in the first place is LINQ; we want to be able to do a simple syntactic transformation on a query comprehension into a method call with lambdas, and let the method type inference engine work out the types of all the lambda parameters. None of the LINQ methods generated have delegates with out or ref parameters.

So, we have no compelling reason to do the feature. Delegates which have out/ref parameters are relatively rare. And assignment of lambdas to those delegates is rarer still. So this is a feature that we don't need, and that benefits almost no one.

C# 3 was the "long pole" on the Visual Studio schedule; we had the most number of days of work scheduled of any team that ships a component in VS. That meant that every day we slipped the schedule, the entire division slipped. That was a powerful disincentive to spending time on unnecessary features that benefitted no one. So the work was never done.

I agree that it would be nice to be more consistent here, but it's unlikely to happen. We have many higher priorities.

like image 127
Eric Lippert Avatar answered Oct 18 '22 02:10

Eric Lippert