<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <font size="4"><font face="monospace">John pulled a nice
        Jedi-mind-trick on me, and pointed out that we actually have two
        creation expressions for arrays:<br>
        <br>
            new Foo[n]<br>
            new Foo[] { a0, .., an }<br>
        <br>
        and that if we are dualizing, then we should have these two
        patterns: <br>
        <br>
            new Foo[] { P0, ..., Pn }  // matches arrays of exactly
        length N<br>
            new Foo[P]                 // matches arrays whose length
        match P<br>
        <br>
        but that neither <br>
        <br>
            new Foo[] { P, Q, ... }   // previous suggestion<br>
        nor  <br>
            new Foo[L] { P, Q }       // current suggestion<br>
        <br>
        correspond to either of those, which suggests that we may have
        prematurely optimized the pattern form.  The rational
        consequence of this observation is to do <br>
        <br>
      </font></font><font size="4"><font face="monospace"><font size="4"><font face="monospace">    new Foo[] { P0, ..., Pn }  // matches
            arrays of exactly length N<br>
            <br>
            now (which is also the basis of varargs patterns), and once
            we have constant patterns (which are kind of required for
            the second form to be all that useful), come back for
            `Foo[P]`.  <br>
            <br>
            <br>
          </font></font></font></font>
    <div class="moz-cite-prefix">On 9/6/2022 5:11 PM, Brian Goetz wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:ee49d374-13cb-c832-8d9c-5d5679e0af9f@oracle.com">
      
      <font size="4"><font face="monospace">We dropped this out of the
          record patterns JEP, but I think it is time to revisit this. 
          <br>
          <br>
          The concept of array patterns was pretty straightforward; they
          mimic the nesting and exhaustiveness rules of record patterns,
          they are just a different sort of container for nested
          patterns.  And they have an obvious duality with array
          creation expressions.  <br>
          <br>
          The main open question here was how we distinguish between
          "match an array of length exactly N" (where there are N nested
          patterns) and "match an array of length at least N".  We toyed
          with the idea of a "..." indicator to mean "more elements",
          but this felt a little forced and opened new questions.  <br>
          <br>
          It later occurred to me that there is another place to nest a
          pattern in an array pattern -- to match (and bind) the
          length.  In the following, assume for sake of exposition that
          "_" is the "any" pattern (matches everything, binds nothing)
          and that we have some way to denote a constant pattern, which
          I'll denote here with a constant literal.  <br>
          <br>
          There is an obvious place to put this (optional) pattern: in
          between the brackets.  So:<br>
          <br>
              case String[1] { P }:<br>
                          ^ a constant pattern<br>
          <br>
          would match string arrays of length 1 whose sole element
          matches P.  And<br>
        </font></font><br>
      <font size="4"><font face="monospace"><font size="4"><font face="monospace">    case String[] { P, Q }<br>
              <br>
              would match string arrays of length exactly 2, whose first
              two elements match P and Q respectively.  (If the length
              pattern is not specified, we infer a constant pattern
              whose constant is equal to the length of the nested
              pattern list.)  <br>
              <br>
              Matching a target to `String[L] { P0, .., Pn }` means<br>
              <br>
                  x instanceof String[] arr<br>
                      && arr.length matches L<br>
                      && arr.length >= n<br>
                      && arr[0] matches P0<br>
                      && arr[1] matches P1<br>
                      ...<br>
                      && arr[n] matches Pn<br>
              <br>
              More examples:<br>
            </font></font><br>
              case String[int len] { P }<br>
          <br>
          would match string arrays of length >= 1 whose first
          element matches P, and further binds the array length to
          `len`.  <br>
          <br>
              case String[_] { P, Q } <br>
          <br>
          would match string arrays of any length whose first two
          elements match P and Q.  <br>
          <br>
              case String[3] { }<br>
                          ^constant pattern<br>
          <br>
          matches all string arrays of length 3.<br>
          <br>
          <br>
          This is a more principled way to do it, because the length is
          a part of the array and deserves a chance to match via nested
          patterns, just as with the elements, and it avoid trying to
          give "..." a new meaning.  <br>
          <br>
          The downside is that it might be confusing at first (though
          people will learn quickly enough) how to distinguish between
          an exact match and a prefix match.  <br>
          <br>
          <br>
          <br>
        </font></font><br>
      <div class="moz-cite-prefix">On 1/5/2021 1:48 PM, Brian Goetz
        wrote:<br>
      </div>
      <blockquote type="cite" cite="mid:5f55e727-8a29-3bdf-57ec-6ec6245ef5c5@oracle.com"> <font size="+1"><font face="monospace">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.)<br>
            <br>
            ## Array Patterns<br>
            <br>
            If we want to create a new array, we do so with an array
            construction expression:<br>
            <br>
                new String[] { "a", "b" }<br>
            <br>
            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:<br>
            <br>
                if (arr instanceof String[] { var a, var b }) { ... }<br>
            <br>
            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.  <br>
            <br>
            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<br>
          </font></font><br>
        <font size="+1"><font face="monospace"><font size="+1"><font face="monospace">    if (arr instanceof String[] { var
                a, var b, ... }) <br>
                <br>
                to indicate "more".  The "..." matches zero or more
                elements and binds nothing.<br>
                <br>
                <digression><br>
              </font></font></font></font>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.<br>
        <font size="+1"><font face="monospace"><font size="+1"><font face="monospace"><font size="+1"><font face="monospace"><font size="+1"><font face="monospace"></digression></font></font></font></font><br>
                <br>
                Here's an example from the JDK that could use this
                effectively:<br>
                <br>
                String[] limits = limitString.split(":");<br>
                try {<br>
                    switch (limits.length) {<br>
                        case 2: {<br>
                            if (!limits[1].equals("*"))<br>
                                setMultilineLimit(MultilineLimit.DEPTH,
                Integer.parseInt(limits[1]));<br>
                        }<br>
                        case 1: {<br>
                            if (!limits[0].equals("*"))<br>
                                setMultilineLimit(MultilineLimit.LENGTH,
                Integer.parseInt(limits[0]));<br>
                        }<br>
                    }<br>
                }<br>
                catch(NumberFormatException ex) {<br>
                    setMultilineLimit(MultilineLimit.DEPTH, -1);<br>
                    setMultilineLimit(MultilineLimit.LENGTH, -1);<br>
                }<br>
                <br>
                becomes (eventually)<br>
              </font></font></font></font><br>
        <font size="+1"><font face="monospace"><font size="+1"><font face="monospace"><font size="+1"><font face="monospace">   
                    switch (limitString.split(":")) {<br>
                            case String[] { var _, Integer.parseInt(var
                    i) } -> setMultilineLimit(DEPTH, i);<br>
                  </font></font><font size="+1"><font face="monospace"> 
                          case String[] { </font></font><font size="+1"><font face="monospace"><font size="+1"><font face="monospace">Integer.parseInt(var i)</font></font>
                    } -> setMultilineLimit(LENGTH, i);<br>
                            default -> { setMultilineLimit(DEPTH,
                    -1); setMultilineLimit(LENGTH, -1); }<br>
                        }<br>
                    <br>
                    Note how not only does this become more compact, but
                    the unchecked "NumberFormatException" is folded into
                    the match, rather than being a separate concern.<br>
                    <br>
                    <br>
                    ## Varargs patterns<br>
                    <br>
                    Having array patterns offers us a natural way to
                    interpret deconstruction patterns for varargs
                    records.  Assume we have:<br>
                    <br>
                        void m(X... xs) { }<br>
                    <br>
                    Then a varargs invocation<br>
                    <br>
                        m(a, b, c)<br>
                    <br>
                    is really sugar for<br>
                    <br>
                        m(new X[] { a, b, c })<br>
                    <br>
                    So the dual of a varargs invocation, a varargs
                    match, is really a match to an array pattern.  So
                    for a record<br>
                    <br>
                        record R(X... xs) { }<br>
                    <br>
                    a varargs match:<br>
                    <br>
                        case R(var a, var b, var c): <br>
                    <br>
                    is really sugar for an array match:<br>
                    <br>
                        case R(X[] { var a, var b, var c }): <br>
                    <br>
                    And similarly, we can use our "more arity"
                    indicator:<br>
                    <br>
                        case R(var a, var b, var c, ...):<br>
                    <br>
                    to indicate that there are at least three elements.<br>
                    <br>
                    <br>
                  </font></font></font></font></font></font> </blockquote>
      <br>
    </blockquote>
    <br>
  </body>
</html>