Allow case constants as nested patterns?

Sebastian Fischer mail at sebfisch.de
Thu Nov 2 11:13:50 UTC 2023


Hello.

I would like to improve my understanding of the interaction of two JEPs:
Pattern matching for switch and Record patterns.

I am new to this list so might have missed previous discussion about this
but could not find what I was looking for in the archives.

JEP 441 shows the following grammar for switch labels.

SwitchLabel:
  case CaseConstant { , CaseConstant }
  case null [, default]
  case Pattern [ Guard ]
  default

JEP 440 shows the following grammar for patterns.

Pattern:
  TypePattern
  RecordPattern

TypePattern:
  LocalVariableDeclaration

RecordPattern:
  ReferenceType ( [ PatternList ] )

PatternList :
  Pattern { , Pattern }

As a consequence it is not possible to have case constants in the pattern
list of a record pattern. For example consider the following definitions
modeling (a simplified version of) boolean expressions.

sealed interface BoolExpr {
    enum Constant implements BoolExpr { TRUE, FALSE }
    record And(BoolExpr left, BoolExpr right) implements BoolExpr {}

    default BoolExpr recursively(UnaryOperator<BoolExpr> transform) {
        return transform.apply(switch (this) {
            case Constant c -> c;
            case And(var left, var right) -> new And(
                left.recursively(transform),
                right.recursively(transform)
            );
        });
    }

    default BoolExpr shortCircuit() {
        return recursively(expr -> switch (expr) {
            case And(var left, var unused)
                when left == Constant.FALSE -> Constant.FALSE;
            default ->
                expr;
        });
    }
}

In the definition of `shortCircuit` (which does partial evaluation) we need
to use a guard to check if the left argument of `And` is false.

Instead of using an enum, we can model constants as empty records as
follows.

    sealed interface Constant extends BoolExpr permits True, False {}
    record True() implements Constant {}
    record False() implements Constant {}

Now we can write `shortCircuit` using a nested record pattern.

    default BoolExpr shortCircuit() {
        return recursively(expr -> switch (expr) {
            case And(False(), var unused) -> new False();
            default -> expr;
        });
    }

It would be convenient to be able to use a nested pattern instead of a
guard with the original definition using an enum for constants. Here is a
hypothetical implementation of `shortCircuit` that is currently not
supported.

    default BoolExpr shortCircuit() {
        return recursively(expr -> switch (expr) {
            case And(Constant.FALSE, var unused) -> Constant.FALSE;
            default -> expr;
        });
    }

What are potential problems with allowing case constants as nested patterns?

Kind regards,
Sebastian
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20231102/9f42b6a4/attachment.htm>


More information about the amber-dev mailing list