Array patterns (and varargs patterns)
Brian Goetz
brian.goetz at oracle.com
Tue Jan 5 18:48:29 UTC 2021
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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20210105/938c092e/attachment.htm>
More information about the amber-spec-experts
mailing list