<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <font size="4"><font face="monospace">Obvious correction: the `new`
        in the pattern examples was a cut and paste error, patterns
        don't say `new`.</font></font><br>
    <br>
    <div class="moz-cite-prefix">On 9/10/2022 5:48 AM, Remi Forax wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:2111267205.2346604.1662803300417.JavaMail.zimbra@u-pem.fr">
      
      <div id="zimbraEditorContainer" style="font-family: arial,
        helvetica, sans-serif; font-size: 12pt; color: #000000" class="2">
        <div><br>
        </div>
        <div><br>
        </div>
        <hr id="zwchr" data-marker="__DIVIDER__">
        <div data-marker="__HEADERS__">
          <blockquote style="border-left:2px solid
#1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From:
            </b>"Brian Goetz" <a class="moz-txt-link-rfc2396E" href="mailto:brian.goetz@oracle.com"><brian.goetz@oracle.com></a><br>
            <b>To: </b>"amber-spec-experts"
            <a class="moz-txt-link-rfc2396E" href="mailto:amber-spec-experts@openjdk.java.net"><amber-spec-experts@openjdk.java.net></a><br>
            <b>Sent: </b>Saturday, September 10, 2022 2:16:15 AM<br>
            <b>Subject: </b>Re: Array patterns (and varargs patterns)<br>
          </blockquote>
        </div>
        <div data-marker="__QUOTED_TEXT__">
          <blockquote style="border-left:2px solid
#1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><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]`.  </font></font></font></font></blockquote>
          <div><br>
          </div>
          <div>I like this proposal, it offers a clean separation
            between the array pattern and a future spread pattern (or
            whatever when end up calling it).<br data-mce-bogus="1">
          </div>
          <div><br data-mce-bogus="1">
          </div>
          <div>RĂ©mi<br data-mce-bogus="1">
          </div>
          <div><br data-mce-bogus="1">
          </div>
          <blockquote style="border-left:2px solid
#1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><font size="4"><font face="monospace"><font size="4"><font face="monospace"><br>
                    <br>
                  </font></font></font></font>
            <div class="moz-cite-prefix">On 9/6/2022 5:11 PM, Brian
              Goetz wrote:<br>
            </div>
            <blockquote 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 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>
            <br>
          </blockquote>
        </div>
      </div>
    </blockquote>
    <br>
  </body>
</html>