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

Question: Use of discard in deconstruction syntax #3229

Closed
yaakov-h opened this issue Feb 24, 2020 · 3 comments
Closed

Question: Use of discard in deconstruction syntax #3229

yaakov-h opened this issue Feb 24, 2020 · 3 comments

Comments

@yaakov-h
Copy link
Member

yaakov-h commented Feb 24, 2020

Given the following code sample:

public class C
{
    public int M() {
        var (a, _) = this;
        return _;
    }
    
    public int N() {
        (var a, var _) = this;
        return _;
    }
    
    public int O() {
        (var a, _) = this;
        return _;
    }
    
    public void Deconstruct(out int first, out int second) => throw null;
}

In each method, the deconstruction has two elements, the first of which is always named.

In M, I could see this being interpreted as either a variable named _, or as a discard.

In N, I would expect var _ to declare a variable named _.

In O, I would expect the discard to be used.

However, in all three cases, this is a discard and not a variable declaration.

What's the reason behind var _ in a deconstruction being a discard instead of a variable, and completely overruling the idea of var declaring a variable?

The only commentary I can find on this is a very early LDM, and nothing in the current spec.

@DavidArno
Copy link

What's the reason behind var _ in a deconstruction being a discard instead of a variable, and completely overruling the idea of var declaring a variable?

It's explained by the two rules in your link:

A standalone _ when no _ is defined in scope is a discard
A "designator" var _ or T _ in deconstruction, pattern matching and out vars is a discard

What this means is that T _ and var _ are always discards, even if a variable _ is in scope and _ on its own is only a discard if there is no variable, _, in scope. So it's sort of the opposite way around to what you expected. An example of _ on its own not being a discard is:

using System;

public class C
{
    static void Main() => Console.WriteLine(new C().M());

    public int M() 
    {
        var _ = 3;
        var a = 3;
        (a, _) = this;
        return _;  // returns 2
    }
    
    public void Deconstruct(out int first, out int second) => (first, second) = (1,2);
}

@HaloFour
Copy link
Contributor

In N, I would expect var _ to declare a variable named _.

It was decided that for new features that didn't require keeping compatibility that _ would always be treated as a discard and not an identifier. While this creates an inconsistency in the language it also eliminates the ambiguity and enables using a discard more than once within a method without causing compiler errors trying to declare _ twice.

There's some convo about it here:

dotnet/roslyn#14862
dotnet/roslyn#14794

@yaakov-h
Copy link
Member Author

oh, I didn't think to check old Roslyn issues.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants