Summary
-------
Based on experiences with the several rounds of preview of pattern matching for switch, we propose a few improvements and simplifications. We also propose to make the feature final and permanent.
Problem
-------
Based on the experiences with the previous round of preview of the feature, we currently propose four changes:
- parenthesized patterns should be dropped because they don't bring significant value in the current state of the feature; hence we propose to drop them.
- qualified enum constants should be allowed as case labels. This also impacts switch exhaustivity.
- the exhaustivity is newly defined to fix problems identified in the previous versions.
- inside a guard, variables declared outside of the guard cannot be assigned
The feature will be made final and permanent.
Solution
--------
<h3>Parenthesized Patterns</h3>
The parenthesized patterns will be dropped. They will be removed from:
- the specification
- the implementation in javac
- the Trees API. The ParenthesizedPatternTree API interface has been marked as a preview feature since introduction, and therefore can be removed.
<h3>Qualified Enum Constants</h3>
Qualified enum constants will be allowed as case labels:
enum E1 { A, B, C; }
enum E2 { C, D, E; }
...
Object o = ...;
switch (o) {
case E1.A, E1.B, E1.C -> {}
case E2.C, E2.D -> {}
}
The existing unqualified enum constants will be preserved, in the existing context of an enum switch selector.
The exhaustivity determination will be naturally extended to include qualified enum constants: if all enum constants of an enum type are used in a set of switch constants, the set of switch constants is exhaustive for the given enum type.
<h3>New Definition of Exhaustivity</h3>
The current rules for switch exhaustivity see some obviously not-exhaustive switches as exhaustive. For example, code like:
public class Test {
private int test(R r) {
return switch (r) {
case R(A a, A b) -> 0;
case R(A a, B b) -> 0;
case R(B a, A b) -> 0;
case R(B(String s), B b) -> 0;
};
}
public sealed interface S permits A, B {}
public final class A implements S {}
public record B(Object o) implements S {}
public record R(S a, S b) {}
}
is considered to be exhaustive by the current rules, although the switch is obviously not exhaustive (does not cover `R` with nested `B` in the first component, where the nested component of the `B` is not `String`). New rules are proposed which are solving this problem.
<h3>Variable Assignment in Guards</h3>
The current specification allows to effectively re-assign final variable inside guards (please see [here](https://mail.openjdk.org/pipermail/amber-dev/2023-March/007901.html)). The proposal is to disallow assignment to any variable inside case guards, unless the variable has been declared inside the guard.
<h3>Finalization of the Feature</h3>
The feature has been a preview feature for several releases. The proposal is to finalize it, making it final and permanent.
Specification
-------------
The specification draft is available for convenience [here](https://cr.openjdk.org/~gbierman/jep440%2B441/jep440%2B441-20230509/specs/patterns-switch-record-patterns-jls.html) and is attached as" 20230509 Pattern Matching for switch and Record Patterns.pdf". Please note that, for technical reasons, the specification draft also includes changes for JEP-440 (https://openjdk.org/jeps/440), which are reviewed under CSR JDK-8304401.
The specdiff of API changes is available [here](https://cr.openjdk.org/~jlahoda/8300543/specdiff.00/overview-summary.html) and is attached as specdiff.00.zip. Please note that, for technical reasons, the specdiff also includes changes for JEP-440 (https://openjdk.org/jeps/440), which are reviewed under CSR JDK-8304401.
The feature will be made final and permanent.