views:

323

answers:

2

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

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.
+2  A: 

From Eric Lippert's comment on why declaration and assignment of a var variable cannot be split:

I agree that in principle this could be done, but it is rather more complicated in practice than your quick sketch would indicate. var not only requires that there be an initializer, it also requires that the initializer not refer to the variable. If you have int M(out int) then you can say "int x = M(out x);" but you cannot say "var x = M(out x);" because to do overload resolution on M, we need to know the type of x, which is what we're attempting to figure out. Would it be legal to say "var s; if (b) M(out s); else s = 0;" ?

I'd guess the answer to your question is similar, considering, for example,

D a = (out var x) => x = M(out x);
dtb
I'm not so sure. How do you explain the fact that if you remove the `out` keyword the compiler can make the inference? The delegate type `D` should completely determine the type of `x`.
LBushkin
I'm not convinced that this is the case. Here, we know that we're trying to wind up with something that looks like a `D`. If the result on the right doesn't match up, won't that be obvious? With the `var` example, it could be anything, so the compiler doesn't have any hints about what the "right answer" should look like. [Whoops! LBushkin beat me to the punch!]
John Feminella
+6  A: 

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.

Eric Lippert
I think everyone's acutely aware of how busy you guys are, but it's definitely nice to know that the door isn't closed because of a technical reason, and that it's theoretically possible to do this someday. Thanks for the input, Eric!
John Feminella