6

From https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/:

We allow "discards" as out parameters as well, in the form of a _, to let you ignore out parameters you don’t care about:

p.GetCoordinates(out var x, out _); // I only care about x

Consider the following code:

void Foo(out int i1, out int i2)
{
    i1 = 1;
    i2 = 2;
}

int _;
Foo(out var _, out _);
Console.WriteLine(_); // outputs 2

Questions:

Why is the "discard" out parameter being outputted in this context?

Also, shouldn't there be an "already defined in scope" error for out var _?

int i;
Foo(out var i, out i);
Console.WriteLine(i); // Error: A local variable or function named 'i'
                      // is already defined in this scope
budi
  • 6,351
  • 10
  • 55
  • 80
  • I don't think your code is correct. When you call your `Foo()`, it should most likely be `Foo(out _);`, though I may be completely misinterpreting your problem statement. – krillgar Jun 28 '17 at 16:48
  • `_` is a valid name for a variable. – Panagiotis Kanavos Jun 28 '17 at 16:53
  • Closing this as a duplicate. Please see [my answer to that duplicate question](https://stackoverflow.com/a/42924200/7122) for details of when `_` is treated as a discard and when it isn't. TL&DR: if you change the line to `Foo(out var _, out var _);` then both parameters are treated as discards even when a `_` variable is in scope. `out _` is only treated as a discard when no `_` is in scope, otherwise it refers to the variable. – David Arno Jun 28 '17 at 17:07

1 Answers1

14

Here's the GitHub issue that details the behavior of discards, the relevant parts are:

However, semantically we want this to create an anonymous variable, and shadow any true variable (e.g. parameter or field) from an enclosing scope named _.
...
We have to be careful with these changes so that any program that uses _ as an identifier and is legal today continues to compile with the same meaning under these revised rules.

_ only means "discard this parameter" if you declare it and use it

  • as an identifier in a "designator" (declaration expression), which includes out parameters and deconstruction of tuples and similar
  • as an indentifier in pattern matching (switch ... case int _)
  • apparently also for declaring anonymous delegates that has to take parameters in order to fit a delegate type but where you don't require the actual parameter.

The out var _ is one of these into this category.

However, int _; is a separate statement, and thus this signals that you "care" about this variable and thus it isn't a discard.

Thus you get a normal variable with the name _, which is still legal. This gets the value 2 from the method call, as expected.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825