-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Proposal: omit 'var' from nested 'var' patterns inside positional patterns #1052
Comments
Typos in positional patterns becoming new variables not errors strikes me a very grave (and definite) drawback, which would present unfamiliar behaviour which would undoubtedly lead to hard-to-find bugs. The static checker is there to help us, and it can't help us if we don't tell it what we want to do, and we can't do that if what we type can be ambiguous. C# is a relatively good language with an old and relatively helpful static checker, and the proposed would be a surprise to anyone that stumbles (perhaps in fit of rage at their compiler) across the behaviour when they 'make a typo' and assume they haven't because they know that the C# compiler isn't so useless as to let them get away with assigning an undeclared variable. A further implication of this drawback is that it can result in the
I would prefer that (if my understanding of explicit tuple deconstruction is correct (I've yet to use it in real code, and honestly don't anticipate doing so)) something more similar to the
Personally I deplore this syntax as well (just personal taste), but it is unambiguous, so you have to make 2 errors to not notice you've shot yourself in the foot, and the behaviour can't be changed by any code above it. There is a lot of sense (I think) in requiring that the deconstructed 'variables' are new variables/readonly-bindings, though it isn't necessarily the right thing in the context of C#. |
We're not planning to have a |
Will the reasons for that (rather depressing) decision by the LDM ever be shared with the community, or is your statement here the extent of the communication from the team? |
@DavidArno It was discussed in the context of the scoping rules for pattern variables, and (our consideration of the related guard statement) is part of the reason we are considering an |
As for the specific examples:
that's a good example of why the
this can be expressed var address = email.Address; or, if you're a bit of a masochist, email.Deconstruct(out var address);
this can be written var (x2, y2) = p; |
Your examples aren't equivalent though, eg var (x1, y1) = p;
let Point(x2, y2) = p; creates Further, using an example domain object from a post by Mark Seeman, by having if (!UserName.TryParse(name, out var username)) throw new SomeException("Not a valid name);
// use "leaked" username here could be replaced with the far more elegant: let Username(username) = name else throw new SomeException("Not a valid name);
// use username here Of course the "leaky out var" boat has sailed, but "we already have a clunky way of doing things" seems a pretty poor excuse for not offering an elegant way of doing the same thing. |
Regarding: void MyMethod(string name)
// snip
let Thing(name) = h; // oops, just overwrote my parameters!
// snip
Console.Writeline(name); My understanding of how void MyMethod(string name)
// snip
if (h is Thing(name)) // oops, just overwrote my parameters, because I forget "var"
// snip
Console.Writeline(name); |
So to be clear on #1052 (comment) above, if I understand it correctly, you won't need to repeat // if the target type is known to be a Point,
case Point(var x, var y):
// would be equivalent to
case var (x, y): However, for single out deconstructions, if we require type name to disambiguate ( #1054 (comment)) you still won't need to repeat case C(var celsius): ... |
@DavidArno perhaps I have misunderstood; I was under the impression (as implied by the 'potential drawback') that predefined variables would be overwritten, or error if they were declared in the I have not read too deeply into the positional patterns proposals (not a huge fan, and it's a big topic), but if they act as you describe, then I don't see any great issue (so long as the syntax and semantics are consistent between 'pattern' features), as the developer has to make 2 'errors' to confuse themselves: they have to omit Having anything 'optional' will always inflict misery upon someone, but if there is only one behaviour then there is no concrete issue at present. In the context of Addendum: having just reread the original post and confused myself, I shall quickly lay out my understanding of the 'drawback': (when attempting to overwrite an existing variable) 'typos in positional patterns will become new variables and not errors.' Perhaps the OP misunderstood the proposal if 'always create a new variable' is the intended behaviour? (Or more likely I did) |
I was always under the assumption that when the design of pattern variables changed to mutable and leaky that the necessity of the |
A simple name in a pattern will be interpreted as a reference to a constant declaration (which is taken as the value of a constant pattern). It is an error if no accessible constant declaration is found. This is true no matter where patterns are used in the language. using static System.Int32;
switch (i)
{
case MaxValue: ...
case MinValue: ...
} |
I think you are right. If I can write, if !(name is Username(var username)) throw new SomeException("Not a valid name);
// use "leaked" username here Wanting to write it as: let Username(username) = name else throw new SomeException("Not a valid name);
// use username here really just becomes a case of not wanting to use the "leaky" vars feature. Clearly that feature is here to stay and we lost the argument on it being a bad choice. So it would take a really compelling argument to revive pattern matching via |
@HaloFour @DavidArno You're both on the right track. I would add that I disagree with @HaloFour 's assertion
The previous Point p = null;
var (x, y) = p; // NullReferenceException However, I believe the status quo allows you to avoid "handling failure" for anything you could have done with a single irrefutable pattern and a |
I was referring specifically to the inability to use That's a good point about the potential fallibility of deconstruction, though. Although it's seemingly only a problem if you deconstruct a reference type and any of the types I've done that with so far have been value types, e.g. tuples, |
We are very unlikely to add the A pattern If the type of the matched input is |
|
Yes |
Nice, thank you. |
@orthoxerox, why do you want |
@DavidArno I expect it to deconstruct the rhs into |
At the very least it should be allowed inside
let
statements, since this will match the style of tuple deconstruction:var
would look superfluous:Potential drawbacks:
Typos in positional patterns will become new variables and not errors.
The text was updated successfully, but these errors were encountered: