As we get into the next round of pattern matching, I'd like to opportunistically attach another sub-feature: array patterns.  (This also bears on the question of "how would varargs patterns work", which I'll address below, though they might come later.)

## Array Patterns

If we want to create a new array, we do so with an array construction expression:

    new String[] { "a", "b" }

Since each form of aggregation should have its dual in destructuring, the natural way to represent an array pattern (h/t to AlanM for suggesting this) is:

    if (arr instanceof String[] { var a, var b }) { ... }

Here, the applicability test is: "are you an instanceof of String[], with length = 2", and if so, we cast to String[], extract the two elements, and match them to the nested patterns `var a` and `var b`.   This is the natural analogue of deconstruction patterns for arrays, complete with nesting.

Since an array can have more elements, we likely need a way to say "length >= 2" rather than simply "length == 2".  There are multiple syntactic ways to get there, for now I'm going to write

    if (arr instanceof String[] { var a, var b, ... })

to indicate "more".  The "..." matches zero or more elements and binds nothing.

<digression>
People are immediately going to ask "can I bind something to the remainder"; I think this is mostly an "attractive distraction", and would prefer to not have this dominate the discussion.
</digression>

Here's an example from the JDK that could use this effectively:

String[] limits = limitString.split(":");
try {
    switch (limits.length) {
        case 2: {
            if (!limits[1].equals("*"))
                setMultilineLimit(MultilineLimit.DEPTH, Integer.parseInt(limits[1]));
        }
        case 1: {
            if (!limits[0].equals("*"))
                setMultilineLimit(MultilineLimit.LENGTH, Integer.parseInt(limits[0]));
        }
    }
}
catch(NumberFormatException ex) {
    setMultilineLimit(MultilineLimit.DEPTH, -1);
    setMultilineLimit(MultilineLimit.LENGTH, -1);
}

becomes (eventually)

switch (limitString.split(":")) {
        case String[] { var _, Integer.parseInt(var i) } -> setMultilineLimit(DEPTH, i);   case String[] { Integer.parseInt(var i) } -> setMultilineLimit(LENGTH, i);         default -> { setMultilineLimit(DEPTH, -1); setMultilineLimit(LENGTH, -1); }
    }

Note how not only does this become more compact, but the unchecked "NumberFormatException" is folded into the match, rather than being a separate concern.


## Varargs patterns

Having array patterns offers us a natural way to interpret deconstruction patterns for varargs records. Assume we have:

    void m(X... xs) { }

Then a varargs invocation

    m(a, b, c)

is really sugar for

    m(new X[] { a, b, c })

So the dual of a varargs invocation, a varargs match, is really a match to an array pattern.  So for a record

    record R(X... xs) { }

a varargs match:

    case R(var a, var b, var c):

is really sugar for an array match:

    case R(X[] { var a, var b, var c }):

And similarly, we can use our "more arity" indicator:

    case R(var a, var b, var c, ...):

to indicate that there are at least three elements.


Reply via email to