Proposal: Permit variable declarations under disjunctive patterns #8621
Replies: 19 comments
-
cc @333fred |
Beta Was this translation helpful? Give feedback.
-
I will champ ion this. |
Beta Was this translation helpful? Give feedback.
-
I imagine we can crib a lot of the rules/spec from F# since they offer this functionality? |
Beta Was this translation helpful? Give feedback.
-
@HaloFour Definitely. F# specification on the subject did help a lot already.
Beyond that, we are diverging from F# specification because in F# it's an error if you don't have an identical set on each side, but in C# we could make additional variables unassigned in that case. This is useful in a switch statement with a |
Beta Was this translation helpful? Give feedback.
-
Lol @CyrusNajmabadi I had already told alrz I'd champion this. It's mine! No fair waking up before me. |
Beta Was this translation helpful? Give feedback.
-
WFM :) I was championing in case no one else picked it up. But if you want it, go for it :) |
Beta Was this translation helpful? Give feedback.
-
I want us to address this scenario! I am a bit concerned about a feature that has multiple declarations of the same variable, so I would want to consider alternatives that didn't do that. For instance, maybe we have a pattern that can match into an existing variable if the type is right. E.g. (just thinking out loud here): e switch
{
(int i, 0) or (0, i) => i,
} Where specifying an existing variable matches into that variable. Perhaps we would only allow it if the variable is not already assigned, to avoid pattern matching having side effects. I'm not saying this is better, but it has different trade-offs, and we should consider our options. |
Beta Was this translation helpful? Give feedback.
-
Some thoughts on that syntax:
|
Beta Was this translation helpful? Give feedback.
-
Would that mean enabling using existing variables in pattern variables in general? int i;
e switch {
(i, 0) or (0, i) => i
} |
Beta Was this translation helpful? Give feedback.
-
What if I want to match instead of assign? readonly int i = 0;
e switch {
(i, 0) or (0, i) => ...
} And that already works for constants with the exact same syntax. I've suggested |
Beta Was this translation helpful? Give feedback.
-
Exactly, that syntax wades into the territory of requests to allow existing variables to be used in patterns instead of just constants, as well as being able to assign patterns into existing variables. |
Beta Was this translation helpful? Give feedback.
-
And to be clear, the said variables are usually defined outside of the pattern itself and likely unassigned (e.g. out parameters) I'd even say that if it ever become a thing, it should be disallowed to reassign pattern variables, that'll make the pattern itself difficult to reason about and hard to follow where such variables are assigned and possibly reassigned. So I favor "multiply declared variables" syntax where we explicitly re-declare variables, rather than implicitly re-assigning them. |
Beta Was this translation helpful? Give feedback.
-
From LDM:
It seems like to allow this we only need to relax the existing scoping rules around pattern variables to enable multi-declarations and handle definite-assignment accordingly. i.e. In other words, the rules that flag those name conflicts are already there, we only need to relax those existing scoping rules. Having said that, the support for overlapping variables across separate patterns just falls out of the fact that they share the same scope. Unless we want to disallow it explicitly.
|
Beta Was this translation helpful? Give feedback.
-
We still need the specese.
Consider: if (o is (not null, null) a or (null, not null) a) {} Also remember the |
Beta Was this translation helpful? Give feedback.
-
I want to add that I wish I could reassign variable. So that I could chain it in Instead of var a = GetFrom0();
if(a == null)
a = GetFrom1();
if(a == null)
a = GetFrom2();
if(a == null)
return;
// DoSomething with a I could just if(GetFrom0() is var a || GetFrom1() is {} a || GetFrom2() is {} a) // Should it require reassign to be {} only ?
{
// DoSomething with a
} |
Beta Was this translation helpful? Give feedback.
-
Can't you use: if ((GetFrom0() ?? GetFrom1() ?? GetFrom2()) is var a)
{
// DoSomething with a
} |
Beta Was this translation helpful? Give feedback.
-
That's the second part of the proposal where you could possibly redeclare pattern variables and they assign to the same local
|
Beta Was this translation helpful? Give feedback.
-
@alrz Oh then sorry I miss that part |
Beta Was this translation helpful? Give feedback.
-
@spydacarnage Not only that sometime I want to do something like this void DoSomething(SomeObject obj)
{
if(obj != null || GetFrom0() is {} obj || GetFrom1() is {} obj || GetFrom2() is {} obj) // reassign variable
{
// DoSomething with obj
}
} And there could be more complex logic in between void DoSomething(SomeObject obj)
{
if(obj != null || (GetFrom0() is {} obj && obj.Val0 != null) || (GetFrom1() is {} obj && obj.Val1 != null))
{
// DoSomething with obj
}
} |
Beta Was this translation helpful? Give feedback.
-
Permit variable declarations under disjunctive patterns
Design meetings
https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-11-11.md#variable-declarations-under-disjunctive-patterns
https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-28.md#variable-declarations-under-disjunctive-patterns
https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-09-28.md#ungrouped
https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-10-17.md#permit-variable-declarations-under-disjunctive-patterns
https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-09-06.md#permit-variable-declarations-under-disjunctive-patterns
Beta Was this translation helpful? Give feedback.
All reactions