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

Add pattern-variables.md #4592

Merged
merged 18 commits into from
Oct 4, 2021
70 changes: 70 additions & 0 deletions proposals/pattern-variables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Variable declarations under disjunctive patterns

## Summary

Allow variable declarations under `or` patterns and across `case` labels in a `switch` section.

## Motivation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add some more practical (less abstract) motivating examples.
Looking that the roslyn codebase, we often have a switch expression just to get some value out of different kinds of bound nodes. Many can be found just by searching for "node switch".
But I have to say looking at that search result, most of them don't look like they would benefit from this feature (either they use when clauses for different cases, or they call different property/method overloads in the different cases).


This feature would reduce code duplication where we could use the same piece of code if either of patterns is satisfied. For instance:
```cs
if (e is (int x, 0) or (0, int x))
Use(x);

switch (e)
{
case (int x, 0):
case (0, int x):
Use(x);
alrz marked this conversation as resolved.
Show resolved Hide resolved
break;
}
```
Instead of:

```cs
if (e is (int x, 0))
Use(x);
else
alrz marked this conversation as resolved.
Show resolved Hide resolved
Use(x)

switch (e)
{
case (int x, 0):
Use(x);
break;
case (0, int x):
Use(x);
break;
}
```

## Detailed design

Variables *must* be redeclared under all disjuncitve patterns because assignment of such variables depend on the order of evaluation which is undefined in the context of pattern-matching.

- In a *disjunctive_pattern*, pattern variables declared under the left-hand-side must be redeclared under the right-hand-side.
alrz marked this conversation as resolved.
Show resolved Hide resolved
- In a *switch_section*, pattern variables declared under each case label must be redeclared under every other case label.

In any other case, variable declaration follows the usual scoping rules and is disallowed.

These names can reference either of variables based on the result of the pattern-matching at runtime. Under the hood, it's the same local being assigned in each pattern.

Redeclaring pattern variables is only permitted for variables of the same type.

## Unresolved questions

- How identical these types should be?
- Could we support variable declarations under `not` patterns?
- Could we relax the scoping rules beyond pattern boundaries?
```cs
if (e is (int x, 0) || a is (0, int x))
```
- Could we relax the redeclaration requirement in a switch section?
```cs
case (int x, 0) a when Use(x, a): // ok
case (0, int x) b when Use(x, b): // ok
Use(x); // ok
Use(a); // error; not definitely assigned
Use(b); // error; not definitely assigned
break;
```