Skip to content

Commit 28f278c

Browse files
committed
[patterns] Add if-case statement to proposal.
1 parent 2af79ef commit 28f278c

File tree

1 file changed

+65
-6
lines changed

1 file changed

+65
-6
lines changed

working/0546-patterns/patterns-feature-specification.md

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -434,11 +434,57 @@ Over half of the switch cases in a large corpus of packages contain either a
434434
single return statement or an assignment followed by a break so there is some
435435
evidence this will be useful.
436436

437-
**TODO: Something like an if statement that matches a single pattern and binds
438-
its variables in the then branch.**
437+
### If-case statement
439438

440-
**TODO: Something like a Swift guard-let that matches a single pattern and binds
441-
in the rest of the block or exits if the pattern does not match.**
439+
Often you want to conditionally match and destructure some data, but you only
440+
want to test a value against a single pattern. You can use a `switch` statement
441+
for that, but it's pretty verbose:
442+
443+
```dart
444+
switch (json) {
445+
case [int x, int y]:
446+
return Point(x, y);
447+
}
448+
```
449+
450+
We can make simple uses like this a little cleaner by introducing an if-like
451+
form similar to [if-case in Swift][]:
452+
453+
[if-case in swift]: https://useyourloaf.com/blog/swift-if-case-let/
454+
455+
```dart
456+
if (case [int x, int y] = json) return Point(x, y);
457+
```
458+
459+
It may have an else branch as well:
460+
461+
```dart
462+
if (case [int x, int y] = json) {
463+
print('Was coordinate array $x,$y');
464+
} else {
465+
throw FormatException('Invalid JSON.');
466+
}
467+
```
468+
469+
The grammar is:
470+
471+
```
472+
ifCaseStatement ::= 'if' '(' 'case' matcher '=' expression ')'
473+
statement ('else' statement)?
474+
```
475+
476+
The `expression` is evaluated and matched against `matcher`. If the pattern
477+
matches, then the then branch is executed with any variables the pattern
478+
defines in scope. Otherwise, the else branch is executed if there is one.
479+
480+
Unlike `switch`, this form doesn't allow a guard clause. Guards are important in
481+
switch cases because, unlike nesting an if statement *inside* the switch case, a
482+
failed guard will continue to try later cases in the switch. That is less
483+
important here since the only other case is the else branch.
484+
485+
**TODO: Consider allowing guard clauses here. That probably necessitates
486+
changing guard clauses to use a keyword other than `if` since `if` nested inside
487+
an `if` condition looks pretty strange.**
442488

443489
### Irrefutable patterns ("binders")
444490

@@ -865,8 +911,9 @@ arity of the type of `typeName`.
865911

866912
A pattern always appears in the context of some value expression that it is
867913
being matched against. In a switch statement or expression, the value expression
868-
is the value being switched on. In a variable declaration, the value is the
869-
initializer:
914+
is the value being switched on. In an if-case statement, the value is the result
915+
of the expression to the right of the `=`. In a variable declaration, the value
916+
is the initializer:
870917

871918
```dart
872919
var (a, b) = (1, 2);
@@ -1221,6 +1268,7 @@ that contains the pattern:
12211268
* **Switch statement case**: The guard clause and the statements of the
12221269
subsequent non-empty case body.
12231270
* **Switch expression case**: The guard clause and the case expression.
1271+
* **If-case statement**: The then statement.
12241272
12251273
Multiple switch case patterns may share the same variable scope if their case
12261274
bodies are empty:
@@ -1371,6 +1419,15 @@ behavior.
13711419
expression after it and yield that as the result of the entire switch
13721420
expression.
13731421

1422+
#### If-case statement
1423+
1424+
1. Evaluate the `expression` producing `v`.
1425+
1426+
2. Match the `matcher` pattern against `v`.
1427+
1428+
3. If the match succeeds, evaluate the then `statement`. Otherwise, if there
1429+
is an `else` clause, evaluate the else `statement`.
1430+
13741431
### Matching (refuting and destructuring)
13751432

13761433
At runtime, a pattern is matched against a value. This determines whether or not
@@ -1523,6 +1580,8 @@ main() {
15231580
- Add a shorthand for destructuring a named record field to a variable with
15241581
the same name.
15251582

1583+
- Add if-case statement.
1584+
15261585
### 1.1
15271586

15281587
- Copy editing and clean up.

0 commit comments

Comments
 (0)