Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Out variable declaration with underscore as the name behaves inconsistently #18015

Closed
poke opened this issue Mar 21, 2017 · 6 comments
Closed
Labels
Area-Compilers Resolution-By Design The behavior reported in the issue matches the current design

Comments

@poke
Copy link

poke commented Mar 21, 2017

Triggered by this question on Stack Overflow, we noticed a few inconsistencies when using the new C#7 out variable declaration with an underscore as the variable name (the one used for the discard functionality).

As expected, the following code does not compile since the _ makes the out variable be discarded:

string s = "123";
int.TryParse(s, out _);
Console.WriteLine(_);

However, assigning to _ works for some reason:

string s = "123";
int.TryParse(s, out _);
_ = 2;

Similarly, if you actually declare the underscore as an inline out variable, you get the same result, even though it should be a real variable now:

string s = "123";
int.TryParse(s, out var _);
Console.WriteLine(_); // does not compile
_ = 2; // does compile

There seems to be something weird going on with the syntax parsing there, since the _ is recognized as a discard regardless of whether it’s an actual discard or a variable declaration. And then the behavior to be able to assign something to _ is just odd; the name shouldn’t be available for anything, not even assigning to it.

(I’ve tested this with the most current version of Visual Studio 2017 15.0.0+26228.9)

@pawchen
Copy link
Contributor

pawchen commented Mar 21, 2017

Is this by design?

out var _ means out _, if you have a function that has multiple out parameters, out _ can be used multiple times regardless of the type of the parameters. So my understanding is that, _ can be assigned by anything as long as it's recognized as discard.

The following code compiles

_ = 2;
_ = "wat";
_ = GetSomething();
_ = new Something();

This looks meaningless, but C# 7 adds tupple, so it's possible to

var (a, _, _) = GetSomeTuple();

(int, int, string) GetSomeTuple() => (0, 1, "wat");

@poke
Copy link
Author

poke commented Mar 21, 2017

Huh? Is _ to discard stuff a general language construct now? Is this really an intended change and is this documented somewhere? According to the language specification, _ is a valid identifier, so the following should work according to spec:

var _ = "foo";
Console.WriteLine(_);

This works in both C#6 and C#7. The following fails in C#6 though but compiles fine in C#7:

_ = "asd"; // CS0103 on C#6
Console.WriteLine(_);

That behavior would appear normal and desired to me. An underscore, while being a poor choice for a variable name, is still a valid variable name. And unless I declare that, it shouldn’t work.

For the discarding functionality in out variables and for tuple destructuring, I would expect this to be a special syntax feature that does not actually do anything to a “real” name _.

@hvdijk
Copy link

hvdijk commented Mar 21, 2017

The following fails in C#6 though but compiles fine in C#7:

The first line works in C#7, the second doesn't, because you never declared a variable named _.

It's the same as when var was introduced: when a variable is named var, that variable is used. Otherwise, var acts as a new keyword. That's what's going on with _ too. _ = ""; _ = 1; works and discards two values. var _ = ""; _ = 1; doesn't, the _ = 1; here acts as an attempted assignment to the existing variable, and the type mismatch is diagnosed.

The design notes from Nov 15 (#16674) mention what has been done to avoid errors for existing uses of _.

@gafter
Copy link
Member

gafter commented Mar 22, 2017

Yes, _ is a general discard construct now. You can assign anything to it.

@gafter gafter closed this as completed Mar 22, 2017
@gafter gafter added the Resolution-By Design The behavior reported in the issue matches the current design label Mar 22, 2017
@poke
Copy link
Author

poke commented Mar 22, 2017

Interesting, I did not know that this was the spec’ed intention. Thank you @hvdijk and @gafter!

@jcouv
Copy link
Member

jcouv commented Jul 8, 2017

For reference, here's the feature design doc: https://github.com/dotnet/roslyn/blob/master/docs/features/discards.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers Resolution-By Design The behavior reported in the issue matches the current design
Projects
None yet
Development

No branches or pull requests

6 participants