<div dir="ltr"><div>I have two points that I think may be good to consider in the list of options.<br><br>1. I'm not sure if this was considered, but I find explicit lists of covering patterns<br>rather natural and more flexible than using case as a pattern-modifier.<br><br>Explicit lists may look like:<br><br>````<br>    // Matches declaration "matches (of|empty)" states that<br>    // "of" and "empty" covers full set of Optional<T> values<br>    class Optional<T> matches of|empty {    <br>    }<br>````<br><br>The important feature of explicit lists is that there may be more than one covering set of patterns.<br><br>````<br>    // There can be multiple sets of patterns, were each set covers all possibilities <br>    class List matches headAndTail|empty, initAndLast|empty {<br>        // ...<br>    }<br>    class Glass matches empty|nonEmpty, full|nonFull {<br>        // ...<br>    }<br>````<br><br>2. I think that there is a middle ground between functional and imperative pattern body definition style that may look cumbersome at first, but nevertheless gives you best of both worlds:<br><br>    * deconstructor patterns look dual to constructors<br>    * names from the list of pattern variables are actually used and checked by the compiler<br>    * control flow is still functional, which is more natural<br><br>The downside that is retained from the imperative style is the need for alpha-renaming,<br>but I think we still have to deal with shadowing and renaming local-variable seems natural and easy.<br>    <br>Middle ground may be used like a special form that can be used in the pattern body.<br>This form works mostly the same way as `with`-clause as defined in the "Derived Record Instances" JEP.<br><br>Here is the long list of examples to fully illustrate different interactions:<br><br>````<br>    class Optional<T> matches (of|empty) {    <br>        public static <T> pattern<Optional<T>> of(T value) {<br>            if (that.isPresent()) {<br>                match {<br>                    value = that.get();<br>                }<br>            }<br>        }<br>    <br>        public static <T> pattern<Optional<T>> empty() {<br>            if (that.isEmpty())<br>                match {}<br>        }<br>    }<br><br>    class Pattern {<br>        public pattern<String> regexMatch(String... groups) {<br>            Matcher m = this.matcher(that);<br>            if (m.matches()) {<br>                match {<br>                    groups =<br>                            IntStream.range(1, m.groupCount())<br>                                    .map(Matcher::group)<br>                                    .toArray(String[]::new);<br>                }<br>            }<br>        }<br>    }<br><br>    class A {<br>        private final int a;<br><br>        public A(int a) {<br>            this.a = a;<br>        }<br>        public pattern A(int a) {<br>            match {<br>                a = that.a;<br>            }<br>        }<br>    }<br><br>    class B extends A {<br>        private final int b;<br><br>        public B(int a, int b) {<br>            super(a);<br>            this.b = b;<br>        }<br><br>        public pattern B(int a, int b) {<br>            if (that instanceof super(var aa)) {<br>                match {<br>                    a = aa;<br>                    b = that.b;<br>                }<br>            }<br>        }<br>    }<br><br>    interface Converter<T,U> {<br>        pattern<T> convert(U u);<br>    }<br>    Converter<Integer, Short> c =<br>        pattern (s) -> {<br>            if (that >= Short.MIN_VALUE && that <= Short.MAX_VALUE)<br>                match {<br>                    s = (short) that;<br>                }<br>        };<br>````<br></div><div><br></div><div>--<br></div><div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div>Victor Nazarov<br></div></div></div></div></div></div><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Mar 29, 2024 at 10:59 PM Brian Goetz <<a href="mailto:brian.goetz@oracle.com">brian.goetz@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><u></u>

  
  <div>
    <font size="4" face="monospace">We now come to the long-awaited
      bikeshed discussion on what member patterns should look like.  <br>
      <br>
      Bikeshed disclaimer for EG: <br>
        - This is likely to evoke strong opinions, so please take pains
      to be especially constructive<br>
        - Long reply-to-reply threads should be avoided even more than
      usual<br>
        - Holistic, considered replies preferred<br>
        - Please change subject line if commenting on a sub-topic or
      tangential<br>
          concern<br>
      <br>
      Special reminders for Remi:<br>
       - Use of words like "should", "must", "shouldn't", "mistake",
      "wrong", "broken"<br>
         are strictly forbidden.  <br>
       - If in doubt, ask questions first.  <br>
      <br>
      Notes for external observers:<br>
       - This is a working document for the EG; the discussion may
      continue for a<br>
         while before there is an official proposal.  Please be patient.<br>
      <br>
      <br>
      # Pattern declaration: the bikeshed<br>
      <br>
      We've largely identified the model for what kinds of patterns we
      need to<br>
      express, but there are still several degrees of freedom in the
      syntax.<br>
      <br>
      As the model has simplified during the design process, the space
      of syntax<br>
      choices has been pruned back, which is a good thing.  However,
      there are still<br>
      quite a few smaller decisions to be made.  Not all of the
      considerations are<br>
      orthogonal, so while they are presented individually, this is not
      a "pick one<br>
      from each column" menu.  <br>
      <br>
      Some of these simplifications include:<br>
      <br>
       - Patterns with "input arguments" have been removed; another way
      to get to what<br>
         this gave us may come back in another form.  <br>
       - I have grown increasingly skeptical of the value of the
      imperative `match`<br>
         statement.  With better totality analysis, I think it can be
      eliminated.<br>
      <br>
      We can discuss these separately but I would like to sync first on
      the broad<br>
      strokes for how patterns are expressed.<br>
      <br>
      ## Object model requirements<br>
      <br>
      As outlined in "Towards Member Patterns", the basic model is that
      patterns are<br>
      the dual of other executable members (constructors, static
      methods, instance<br>
      methods.)  While they are like methods in that they have inputs,
      outputs, names,<br>
      and an imperative body, they have additional degrees of freedom
      that<br>
      constructors and methods lack: <br>
      <br>
       - Patterns are, in general, _conditional_ (they can succeed or
      fail), and only<br>
         produce bindings (outputs) when they succeed.  This
      conditionality is<br>
         understood by the language's flow analysis, and is used for
      computing scoping<br>
         and definite assignment.<br>
       - Methods can return at most one value; when a pattern completes
      successfully,<br>
         it may bind multiple values.<br>
       - All patterns have a _match candidate_, which is a
      distinguished,<br>
         possibly-implicit parameter.  Some patterns also have a
      receiver, which is<br>
         also a distinguished, possibly-implicit parameter.  In some
      such cases the<br>
         receiver and match candidate are aliased, but in others these
      may refer to<br>
         different objects.<br>
      <br>
      So a pattern is a named executable member that takes a _match
      candidate_ as a<br>
      possibly-implicit parameter, maybe takes a receiver as an implicit
      parameter,<br>
      and has zero or more conditional _bindings_.  Its body can perform
      imperative<br>
      computation, and can terminate either with match failure or
      success.  In the<br>
      success case, it must provide a value for each binding.<br>
      <br>
      Deconstruction patterns are special in many of the same ways
      constructors are:<br>
      they are constrained in their name, inheritance, and probably
      their<br>
      conditionality (they should probably always succeed).  Just as the
      syntax for<br>
      constructors differs slightly from that of instance methods, the
      syntax for<br>
      deconstructors may differ slightly from that of instance
      patterns.  Static<br>
      patterns, like static methods, have no receiver and do not have
      access to the<br>
      type parameters of the enclosing class.  <br>
      <br>
      Like constructors and methods, patterns can be overloaded, but in
      accordance<br>
      with their duality to constructors and methods, the overloading
      happens on the<br>
      _bindings_, not the inputs.  <br>
      <br>
      ## Use-site syntax<br>
      <br>
      There are several kinds of type-driven patterns built into the
      language: type<br>
      patterns and record patterns.  A type pattern in a `switch` looks
      like:<br>
      <br>
          case String s: ...<br>
      <br>
      And a record pattern looks like:<br>
      <br>
          case MyRecord(P1, P2, ...): ...<br>
      <br>
      where `P1..Pn` are nested patterns that are recursively matched to
      the<br>
      components of the record.  This use-site syntax for record
      patterns was chosen<br>
      for its similarity to the construction syntax, to highlight that a
      record<br>
      pattern is the dual of record construction.  <br>
      <br>
      **Deconstruction patterns.**  The simplest kind of member pattern,
      a<br>
      deconstruction pattern, will have the same use-site syntax as a
      record pattern;<br>
      record patterns can be thought of as a deconstruction pattern
      "acquired for<br>
      free" by records, just as records do with constructors, accessors,
      object<br>
      methods, etc.  So the use of a deconstruction pattern for `Point`
      looks like:<br>
      <br>
          case Point(var x, var y): ...<br>
      <br>
      whether `Point` is a record or an ordinary class equipped with a
      suitable<br>
      deconstruction pattern.  <br>
      <br>
      **Static patterns.**  Continuing with the idea that the
      destructuring syntax<br>
      should evoke the aggregation syntax, there is an obvious candidate
      for the<br>
      use-site syntax for static patterns: <br>
      <br>
          case Optional.of(var e): ...<br>
          case Optional.empty(): ...<br>
      <br>
      **Instance patterns.**  Uses of instance patterns will likely come
      in two forms,<br>
      analogous to bound and unbound instance method references,
      depending on whether<br>
      the receiver and the match candidate are the same object.  In the
      unbound form,<br>
      used when the receiver is the same object as the match candidate,
      the pattern<br>
      name is qualified by a _type_:<br>
      <br>
      ```<br>
      Class<?> k = ...<br>
      switch (k) { <br>
          // Qualified by type<br>
          case Class.arrayClass(var componentType): ...<br>
      }<br>
      ```<br>
      <br>
      This means that we _resolve_ the pattern `arrayClass` starting at
      `Class` and<br>
      _select_ the pattern using the receiver, `k`.  We may also be able
      to omit the<br>
      class qualifier if the static type of the match candidate is
      sufficient to<br>
      resolve the desired pattern.<br>
      <br>
      In the bound form, used when the receiver is distinct from the
      match candidate,<br>
      the pattern name is qualified with an explicit _receiver
      expression_.  As an<br>
      example, consider an interface that captures primitive widening
      and narrowing<br>
      conversions, such as those between `int` and `long`.  In the
      widening direction,<br>
      conversion is unconditional, so this can be modeled as a method
      from `int` to<br>
      `long`.  In the other direction, conversion is conditional, so
      this is better<br>
      modeled as a _pattern_ whose match candidate is `long` and which
      binds an `int`<br>
      on success.  Since these are instance methods of some class (say,<br>
      `NumericConversion<T,U>`), we need to provide the receiver
      instance in order to<br>
      resolve the pattern:<br>
      <br>
      ```<br>
      NumericConversion<int, long> nc = ...<br>
      <br>
      switch (aLong) { <br>
          case nc.narrowed(int i): <br>
          ...<br>
      }<br>
      ```<br>
      <br>
      The explicit receiver syntax would also be used if we exposed
      regular expression<br>
      matching as a pattern on the `j.u.r.Pattern` object (the name
      collision on<br>
      `Pattern` is unfortunate).  Imagine we added a `matching` instance
      pattern to<br>
      `j.u.r.Pattern`; then we could use it in `instanceof` as follows:
      <br>
      <br>
      ```<br>
      static final java.util.regex.Pattern P =
      Pattern.compile("(a*)(b*)");  <br>
      ...<br>
      if (aString instanceof P.matching(String as, String bs)) { ... }<br>
      ```<br>
      <br>
      Each of these use-site syntaxes is modeled after the use-site
      syntax for a<br>
      method invocation or method reference.<br>
      <br>
      ## Declaration-site syntax<br>
      <br>
      To avoid being biased by the simpler cases, we're going to work
      all the cases<br>
      concurrently rather than starting with the simpler cases and
      working up.  (It<br>
      might seem sensible to start with deconstructors, since they are
      the "easy"<br>
      case, but if we did that, we would likely be biased by their
      simplicity and then<br>
      find ourselves painted into a corner.)  As our example gallery, we
      will consider:<br>
      <br>
       - Deconstruction pattern for `Point`;<br>
       - Static patterns for `Optional::of` and `Optional::empty`;<br>
       - Static pattern for "power of two" (illustrating a computations
      where success<br>
         or failure, and computation of bindings, cannot easily be
      separated);<br>
       - Instance pattern for `Class::arrayClass` (used unbound);<br>
       - Instance pattern for `Pattern::matching` on regular expressions
      (used bound).<br>
       <br>
      Member patterns, like methods, have _names_.  (We can think of
      constructors as<br>
      being named for their enclosing classes, and the same for
      deconstructors.)  All<br>
      member patterns have a (possibly empty) ordered list of
      _bindings_, which are<br>
      the dual of constructor or method parameters.  Bindings, in turn,
      have names and<br>
      types.  And like constructors and methods, member patterns have a
      _body_ which<br>
      is a block statement.  Member patterns also have a _match
      candidate_, which is a<br>
      likely-implicit method parameter.  <br>
      <br>
      ### Member patterns as inverse methods and constructors<br>
      <br>
      Regardless of syntax, let us remind ourselves that that
      deconstructors are the<br>
      categorical dual to constructors (coconstructors), and pattern
      methods are the<br>
      categorical dual to methods (comethods).  They are dual in their
      structure: a<br>
      constructor or method takes N arguments and produces a result, the
      corresponding<br>
      member pattern consumes a match candidate and (conditionally)
      produces N<br>
      bindings.  <br>
      <br>
      Moreover, they are semantically dual: the return value produced by
      construction<br>
      or factory invocation is the match candidate for the corresponding
      member<br>
      pattern, and the bindings produced by a member pattern are the
      answers to the<br>
      _Pattern Question_ -- "could this object have come from an
      invocation of my<br>
      dual, and if so, with what arguments."  <br>
      <br>
      ### What do we call them?<br>
      <br>
      Given the significant overlap between methods and patterns, the
      first question<br>
      about the declaration we need to settle is how to identify a
      member pattern<br>
      declaration as distinct from a method or constructor declaration. 
      _Towards<br>
      Member Patterns_ tried out a syntax that recognized these as
      _inverse_ methods<br>
      and constructors:<br>
      <br>
          public Point(int x, int y) { ... }<br>
          public inverse Point(int x, int y) { ... }<br>
      <br>
      While this is a principled choice which clearly highlights the
      duality, and one<br>
      that might be good for specification and verbal description, it is
      questionable<br>
      whether this would be a great syntax for reading and writing
      programs.  <br>
      <br>
      A more traditional option is to choose a "noun" (conditional)
      keyword, such as<br>
      `pattern`, `matcher`, `extractor`, `view`, etc:<br>
      <br>
          public pattern Point(int x, int y) { ... }<br>
      <br>
      If we are using a noun keyword to identify pattern declarations,
      we could use<br>
      the same noun for all of them, or we could choose a different one
      for<br>
      deconstruction patterns:<br>
      <br>
          public deconstructor Point(int x, int y) { ... }<br>
      <br>
      Alternately, we could reach for a symbol to indicate that we are
      talking about<br>
      an inverted member.  C++ fans might suggest<br>
      <br>
          public ~Point(int x, int y) { ... }<br>
      <br>
      but this is too cryptic (it's evocative once you see it, but then
      it becomes<br>
      less evocative as we move away from deconstructors towards
      instance patterns.)<br>
      <br>
      If we wish to offer finer-grained control over conditionality, we
      might<br>
      additionally need a `total` / `partial` modifier, though I would
      prefer to avoid<br>
      that.<br>
      <br>
      Of the keyword candidates, there is one that stands out (for good
      and bad)<br>
      because it connects to something that is already in the language:
      `pattern`.  On<br>
      the one hand, using the term `pattern` for the declaration is a
      slight abuse; on<br>
      the other, users will immediately connect it with "ah, so that's
      how I make a<br>
      new pattern" or "so that's what happens when I match against this
      pattern."<br>
      (Lisps would resolve this tension by calling it `defpattern`.)<br>
      <br>
      The others (`matcher`, `view`, `extractor`, etc) are all made-up
      terms that<br>
      don't connect to anything else in the language, for better or
      worse.  If we pick<br>
      one of these, we are asking users to sort out _three_ separate new
      things in<br>
      their heads: (use-site) patterns, (declaration-site) matchers, and
      the rules of<br>
      how patterns and matchers are connected.  Calling them both
      "patterns", despite<br>
      the mild abuse of terminology, ties them together in a way that
      recognizes their<br>
      connection.<br>
      <br>
      My personal position: `pattern` is the strongest candidate here,
      despite some<br>
      flaws.<br>
      <br>
      ### Binding lists and match candidates<br>
      <br>
      There are two obvious alternatives for describing the binding list
      and match<br>
      candidate of a pattern declaration, both with their roots in the
      constructor and<br>
      method syntax: <br>
      <br>
       - Pretend that a pattern declaration is like a method with
      multiple return, and<br>
         put the binding list in the "return position", and make the
      match candidate<br>
         an ordinary parameter;<br>
       - Lean into the inverse relationship between constructors and
      methods (and<br>
         consistency with the use-site syntax), and put the binding list
      in the<br>
         "parameter list position". For static patterns and some
      instance patterns,<br>
         which need to explicitly identify the match candidate type,
      there are several<br>
         sub-options:<br>
         - Lean further into the duality, putting the match candidate
      type in the<br>
           "return position";<br>
         - Put the match candidate type somewhere else, where it is less
      likely to be<br>
           confused for a method return.<br>
      <br>
      The "method-like" approach might look like this:<br>
      <br>
      ```<br>
      class Point { <br>
          // Constructor and deconstructor<br>
          public Point(int x, int y) { ... }<br>
          public pattern (int x, int y) Point(Point target) { ... }<br>
          ...<br>
      }<br>
      <br>
      class Optional<T> { <br>
          // Static factory and pattern<br>
          public static<T> Optional<T> of(T t) { ... }<br>
          public static<T> pattern (T t) of(Optional<T>
      target) { ... }<br>
          ...<br>
      }<br>
      ```<br>
      <br>
      The "inverse" approach might look like:<br>
      <br>
      ```<br>
      class Point { <br>
          // Constructor and deconstructor<br>
          public Point(int x, int y) { ... }<br>
          public pattern Point(int x, int y) { ... }<br>
          ...<br>
      }<br>
      <br>
      class Optional<T> { <br>
          // Static factory and pattern (using the first sub-option)<br>
          public static<T> Optional<T> of(T t) { ... }<br>
          public static<T> pattern Optional<T> of(T t) { ...
      }<br>
          ...<br>
      }<br>
      ```<br>
      <br>
      With the "method-like" approach, the match candidate gets an
      explicit name<br>
      selected by the author; with the inverse approach, we can go with
      a predefined<br>
      name such as `that`.  (Because deconstructors do not have
      receivers, we could by<br>
      abuse of notation arrange for the keyword `this` to refer instead
      to the match<br>
      candidate within the body of a deconstructor.  While this might
      seem to lead to<br>
      a more familiar notation for writing deconstructors, it would
      create a<br>
      gratuitous asymmetry between the bodies of deconstruction patterns
      and those of<br>
      other patterns.)<br>
      <br>
      Between these choices, nearly all the considerations favor the
      "inverse"<br>
      approach:<br>
      <br>
       - The "inverse" approach makes the declaration look like the use
      site.  This<br>
         highlights that `pattern Point(int x, int y)` is what gets
      invoked when you<br>
         match against the pattern use `Point(int x, int y)`.  (This
      point is so<br>
         strong that we should probably just stop here.)<br>
       - The "inverse" members also look like their duals; the only
      difference is the<br>
         `pattern` keyword (and possibly the placement of the match
      candidate type).<br>
         This makes matched pairs much more obvious, and such matched
      pairs will be<br>
         critical both for future language features and for library
      idioms.<br>
       - The method-like approach is suggestive of multiple return or
      tuples, which is<br>
         probably helpful for the first few minutes but actually harmful
      in the long<br>
         term. This feature is _not_ (much as some people would like to
      believe) about<br>
         multiple return or tuples, and playing into this misperception
      will only make<br>
         it harder to truly understand.  So this suggestion ends up
      propping up the<br>
         wrong mental model.  <br>
      <br>
      The main downside of the "inverse" approach is the one-time speed
      bump of the<br>
      unfamiliarity of the inverted syntax.  (The "method-like" syntax
      also has its<br>
      own speed bumps, it is just unfamiliar in different ways.)  But
      unlike the<br>
      advantages of the inverse approach, which continue to add value
      forever, this<br>
      speed bump is a one-time hurdle to get over.  <br>
      <br>
      To smooth out the speed bumps of the inverse approach, we can
      consider moving<br>
      the position of the match candidate for static and (suitable)
      instance pattern<br>
      declarations, such as:<br>
      <br>
      ```<br>
      class Optional<T> { <br>
          // the usual static factory<br>
          public static<T> Optional<T> of(T t) { ... }<br>
      <br>
          // Various ways of writing the corresponding pattern<br>
          public static<T> pattern of(T t) for Optional<T> {
      ... }<br>
          // or ...<br>
          public static<T> pattern(Optional<T>) of(T t) {
      ... }<br>
          // or ...<br>
          public static<T> pattern(Optional<T> that) of(T t)
      { ... }<br>
          // or ...<br>
          public static<T> pattern<Optional<T>> of(T
      t) { ... }<br>
          ...<br>
      }<br>
      ```<br>
      <br>
      (The deconstructor example looks the same with either variant.) 
      Of these,<br>
      treating the match candidate like a "parameter" of "pattern" is
      probably the<br>
      most evocative:<br>
      <br>
      ```<br>
      public static<T> pattern(Optional<T> that) of(T t) {
      ... }<br>
      ```<br>
      <br>
      as it can be read as "pattern taking the parameter
      `Optional<T> that` called<br>
      `of`, binding `T`, and is a short departure from the inverse
      syntax.<br>
      <br>
      The main value of the various rearrangements is that users don't
      need to think<br>
      about things operating in reverse to parse the syntax.  This
      trades some of the<br>
      secondary point (patterns looking almost exactly like their
      inverses) for a<br>
      certain amount of cognitive load, while maintaining the most
      important<br>
      consideration: that the declaration site look like the use site.  <br>
      <br>
      For instance pattern declarations, if the match candidate type is
      the same as<br>
      the receiver type, the match candidate type can be elided as it is
      with<br>
      deconstructors.  <br>
      <br>
      My personal position: the "multiple return" version is terrible;
      all the<br>
      sub-variants of the inverse version are probably workable.<br>
      <br>
      ### Naming the match candidate<br>
      <br>
      We've been assuming so far that the match candidate always has a
      fixed name,<br>
      such as `that`; this is an entirely workable approach.  Some of
      the variants are<br>
      also amenable to allowing authors to explicitly select a name for
      the match<br>
      candidate.  For example, if we put the match candidate as a
      "parameter" to the `pattern` keyword, there is an obvious place to
      put the name:<br>
      <br>
      ```<br>
      static<T> pattern(Optional<T> target) of(T t) { ... }<br>
      ```<br>
      <br>
      My personal opinion: I don't think this degree of freedom buys us
      much, and in<br>
      the long run readability probably benefits by picking a fixed name
      like `that`<br>
      and sticking with it.  Even with a fixed name, if there is a
      sensible position<br>
      for the name, allowing users to type `that` for explicitness is
      fine (as we do<br>
      with instance methods, though many people don't know this.)  We
      may even want to<br>
      require it.<br>
      <br>
      ## Body types<br>
      <br>
      Just as there are two obvious approaches for the declaration,
      there are two<br>
      obvious approaches we could take for the body (though there is
      some coupling<br>
      between them.)  We'll call the two body approaches _imperative_
      and<br>
      _functional_.  <br>
      <br>
      The imperative approach treats bindings as initially-DU variables
      that must be<br>
      DA on successful completion, getting their value through ordinary
      assignment;<br>
      the functional approach sets all the bindings at once,
      positionally.  Either<br>
      way, member patterns (except maybe deconstructors) also need a way
      to<br>
      differentiate a successful match from a failed match.  <br>
      <br>
      Here is the `Point` deconstructor with both imperative and
      functional style. The<br>
      functional style uses a placeholder `match` statement to indicate
      a successful<br>
      match and provision of bindings:<br>
      <br>
      ```<br>
      class Point {<br>
          int x, y;<br>
      <br>
          Point(int x, int y) {<br>
              this.x = x;<br>
              this.y = y;<br>
          }<br>
      <br>
          // Imperative style, deconstructor always succeeds<br>
          pattern Point(int x, int y) {<br>
              x = that.x;<br>
              y = that.y;<br>
          }<br>
      <br>
          // Functional style<br>
          pattern Point(int x, int y) {<br>
              match(that.x, that.y);<br>
          }<br>
      }<br>
      ```<br>
      <br>
      There are some obvious differences here.  In the imperative style,
      the dtor body<br>
      looks much more like the reverse of the ctor body. The functional
      style is more<br>
      concise (and amenable to further concision via the "concise method
      bodies"<br>
      mechanism in the future), as well as a number of less obvious
      differences.  For<br>
      deconstructors, the imperative approach is likely to feel more
      natural because<br>
      of the obvious symmetry with constructors.<br>
      <br>
      In reality, it is _premature at this point to have an opinion_,
      because we<br>
      haven't yet seen the full scope of the problem; deconstructors are
      a special<br>
      case in many ways, which almost surely is distorting our initial
      opinion.  As we<br>
      move towards conditional patterns (and pattern lambdas), our
      opinions may flip.<br>
      <br>
      Regardless of which we pick, there are some additional syntactic
      choices to be<br>
      made -- what syntax to use to indicate success (we used `match` in
      the above<br>
      example) or failure.  (We should be especially careful around
      trying to reuse<br>
      words like `return`, `break`, or `yield` because, in the case
      where there are<br>
      zero bindings (which is allowable), it becomes unclear whether
      they mean "fail"<br>
      or "succeed with zero bindings".)  <br>
      <br>
      ### Success and failure<br>
      <br>
      Except for possibly deconstructors, which we may require to be
      total, a pattern<br>
      declaration needs a way to indicate success and failure.  In the
      examples above,<br>
      we posited a `match` statement to indicate success in the
      functional approach,<br>
      and in both examples leaned on the "implicit success" of
      deconstructors (under<br>
      the assumption they always succeed).  Now let's look at the more
      general case to<br>
      figure out what else is needed.<br>
      <br>
      For a static pattern like `Optional::of`, success is conditional. 
      Using<br>
      `match-fail` as a placeholder for "the match failed", this might
      look like<br>
      (functional version):<br>
      <br>
      ```<br>
      public static<T> pattern(Optional<T> that) of(T t) { <br>
          if (that.isPresent())<br>
              match (that.get());<br>
          else<br>
              match-fail;<br>
      }<br>
      ```<br>
      <br>
      The imperative version is less pretty, though.  Using
      `match-success` as a<br>
      placeholder:<br>
      <br>
      ```<br>
      public static<T> pattern(Optional<T> that) of(T t) { <br>
          if (that.isPresent()) {<br>
              t = that.get();<br>
              match-success;<br>
          }<br>
          else<br>
              match-fail;<br>
      }<br>
      ```<br>
      <br>
      Both arms of the `if` feel excessively ceremonial here.  And if we
      chose to not<br>
      make all deconstruction patterns unconditional, deconstructors
      would likely need<br>
      some explicit success as well:<br>
      <br>
      ```<br>
      pattern Point(int x, int y) {<br>
          x = that.x;<br>
          y = that.y;<br>
          match-success;<br>
      }<br>
      ```<br>
      <br>
      It might be tempting to try and eliminate the need for explicit
      success by<br>
      inferring it from whether or not the bindings are DA or not, but
      this is<br>
      error-prone, is less type-checkable, and falls apart completely
      for patterns<br>
      with no bindings.<br>
      <br>
      ### Implicit failure in the functional approach<br>
      <br>
      One of the ceremonial-seeming aspects of `Optional::of` above is
      having to say<br>
      `else match-fail`, which doesn't feel like it adds a lot of
      value.  Perhaps we<br>
      can be more concise without losing clarity.  <br>
      <br>
      Most conditional patterns will have a predicate to determine
      matching, and then<br>
      some conditional code to compute the bindings and claim success. 
      Having to say<br>
      "and if the predicate didn't hold, then I fail" seems like
      ceremony for the<br>
      author and noise for the reader.  Instead, if a conditional
      pattern falls off<br>
      the end without matching, we could treat that as simply not
      matching:<br>
      <br>
      ```<br>
      public static<T> pattern(Optional<T> that) of(T t) { <br>
          if (that.isPresent())<br>
              match (that.get());<br>
      }<br>
      ```<br>
      <br>
      This says what we mean: if the optional is present, then this
      pattern succeeds<br>
      and bind the contents of the `Optional`.  As long as our "succeed"
      construct<br>
      strongly enough connotes that we are terminating abruptly and
      successfully, this<br>
      code is perfectly clear.  And most conditional patterns will look
      a lot like<br>
      `Optional::of`; do some sort of test and if it succeeds, extract
      the state and<br>
      bind it.<br>
      <br>
      At first glance, this "implicit fail" idiom may seem error-prone
      or sloppy.  But<br>
      after writing a few dozen patterns, one quickly tires of saying
      "else<br>
      match-fail" -- and the reader doesn't necessarily appreciate
      reading it either.  <br>
      <br>
      Implicit failure also simplifies the selection of how we
      explicitly indicate<br>
      failure; using `return` in a pattern for "no match" becomes pretty
      much a forced<br>
      move.  We observe that (in a void method), "return" and "falling
      off the end"<br>
      are equivalent; if "falling off the end" means "no match", then so
      should an<br>
      explicit `return`.  So in those few cases where we need to
      explicitly signal "no<br>
      match", we can just use `return`.  It won't come up that often,
      but here's an<br>
      example where it does: <br>
      <br>
      ```<br>
      static pattern(int that) powerOfTwo(int exp) {<br>
          int exp = 0;<br>
      <br>
          if (that < 1)<br>
              return; // explicit fail<br>
      <br>
          while (that > 1) {<br>
              if (that % 2 == 0) {<br>
                  that /= 2;<br>
                  ++exp;<br>
              }<br>
              else<br>
                  return; // explicit fail<br>
          }<br>
          match (exp);<br>
      }<br>
      ```<br>
      <br>
      As a bonus, if `return` as match failure is a forced move, we need
      only select a<br>
      term for "successful match" (which obviously can't be `return`). 
      We could use<br>
      `match` as we have in the examples, or a variant like `matched` or
      `matches`.<br>
      But rather than just creating a new control operator, we have an
      opportunity to<br>
      lean into the duality a little harder, by including the pattern
      syntax in the<br>
      match:<br>
      <br>
      ```<br>
      matches of(that.get());<br>
      ```<br>
      <br>
      or the (optionally?) qualified (inferring type arguments, as we do
      at the use<br>
      site):<br>
      <br>
      ```<br>
      matches Optional.of(that.get());<br>
      ```<br>
      <br>
      These "use the name" approaches trades a small amount of verbosity
      to gain a<br>
      higher degree of fidelity to the pattern use site (and to evoke
      the comethod<br>
      completion.)  <br>
      <br>
      If we don't choose "implicit fail", we would have to invent _two_
      new control<br>
      flow statements to indicate "success" and "failure".  <br>
      <br>
      My personal position: for the functional approach, implicit
      failure both makes<br>
      the code simpler and clearer, and after you get used to it, you
      don't want to go<br>
      back.  Whether we say `match` or `matches` or `matches
      <pattern-name>` are all<br>
      workable, though I like some variant that names the pattern.<br>
      <br>
      ### Implicit success in the imperative approach<br>
      <br>
      In the imperative approach, we can be implicit as well, but it
      feels more<br>
      natural (at least, initially) to choose implicit success rather
      than failure.<br>
      This works great for unconditional patterns:<br>
      <br>
      ```<br>
      pattern Point(int x, int y) {<br>
          x = that.x;<br>
          y = that.y;<br>
          // implicit success<br>
      }<br>
      ```<br>
      <br>
      but not quite as well for conditional patterns:<br>
      <br>
      ```<br>
      static<T> pattern(Optional<T> that) of(T t) { <br>
          if (that.isPresent()) {<br>
              t = that.get();<br>
          }<br>
          else<br>
              match-fail;<br>
          // implicit success<br>
      }<br>
      ```<br>
      <br>
      We can eliminate one of the arms of the if, with the more concise
      (but<br>
      convoluted) inversion:<br>
      <br>
      ```<br>
      static<T> pattern(Optional<T> that) of(T t) { <br>
          if (!that.isPresent()) <br>
              match-fail;<br>
          t = that.get();<br>
          // implicit success<br>
      }<br>
      ```<br>
      <br>
      Just as with the functional approach, if we choose imperative and
      "implicit<br>
      success", using `return` to indicate success is pretty much a
      forced move.  <br>
      <br>
      ### Imperative is a trap<br>
      <br>
      If we assume that functional implies implicit failure, and
      imperative implies<br>
      implicit success, then our choices become: <br>
      <br>
      ```<br>
      class Optional<T> { <br>
          public static<T> Optional<T> of(T t) { ... }<br>
      <br>
          // imperative, implicit success<br>
          public static<T> pattern(Optional<T> that) of(T t)
      { <br>
              if (that.isPresent()) {<br>
                  t = that.get();<br>
              }<br>
              else<br>
                  match-fail;<br>
          }<br>
      <br>
          // functional, implicit failure<br>
          public static<T> pattern(Optional<T> that) of(T t)
      { <br>
              if (that.isPresent())<br>
                  matches of(that.get());<br>
          }<br>
      }<br>
      ```<br>
      <br>
      Once we get past deconstructors, the imperative approach looks
      worse by<br>
      comparison because we need to assign all the bindings (which is
      _O(n)_<br>
      assignments) _and also_ indicate success or failure somehow,
      whereas in the<br>
      functional style all can be done together with a single `matches`
      statement.<br>
      <br>
      Looking at the alternatives, except maybe for unconditional
      patterns, the<br>
      functional example above seems a lot more natural.  The imperative
      approach<br>
      works with deconstructors (assuming they are not conditional), but
      does not<br>
      scale so well to conditionality -- which is the essence of
      patterns.<br>
      <br>
      From a theoretical perspective, the method-comethod duality also
      gives us a<br>
      forceful nudge towards the functional approach.  In a method, the
      method<br>
      arguments are specified as a positional list of expressions at the
      use site: <br>
      <br>
          m(a, b, c)<br>
      <br>
      and these values are invisibly copied into the parameter slots of
      the method<br>
      prior to frame activation.  The dual to that for a comethod to
      similarly convey<br>
      the bindings in a positional list of expressions (as they must
      either all be<br>
      produced or none), where they are copied into the slots provided
      at the use<br>
      site, as is indicated by `matches` in the above examples.  <br>
      <br>
      My personal position: the imperative style feels like a trap.  It
      seems<br>
      "obvious" at first if we start with deconstructors, but becomes
      increasingly<br>
      difficult when we get past this case, and gets in the way of other<br>
      opportunities.  The last gasp before acceptance is the discomfort
      that dtor and<br>
      ctor bodies are written in different styles, but in the rear-view
      mirror, this<br>
      feels like a non-issue.  <br>
      <br>
      ### Derive imperative from functional?<br>
      <br>
      If we start with "functional with implicit failure", we can
      possibly rescue<br>
      imperative by deriving a version of imperative from functional, by
      "overloading"<br>
      the match-success operator.  <br>
      <br>
      If we have a pattern whose binding names are `b1..bn` of types
      `B1..Bn`, then<br>
      the `matches` operator must take a list of expressions `e1..en`
      whose arity and<br>
      types are compatible with `B1..Bn`.  But we could allow `matches`
      to also have a<br>
      nilary form, which would have the effect of being shorthand for <br>
      <br>
          matches <pattern-name>(b1, b2, ..., bn)<br>
      <br>
      where each of `b1..bn` must be DA at the point of matching.  This
      means that we<br>
      could express patterns in either form:<br>
      <br>
      ```<br>
      class Optional<T> { <br>
          public static<T> Optional<T> of(T t) { ... }<br>
      <br>
          // imperative, derived from functional with implicit failure<br>
          public static<T> pattern(Optional<T> that) of(T t)
      { <br>
              if (that.isPresent()) {<br>
                  t = that.get();<br>
                  matches of;<br>
              }<br>
          }<br>
      <br>
          public static<T> pattern(Optional<T> that) of(T t)
      { <br>
              if (that.isPresent())<br>
                  matches of(that.get());<br>
          }<br>
      }<br>
      ```<br>
      <br>
      This flexibility allows users to select a more verbose expression
      in exchange<br>
      for a clearer association of expressions and bindings, though as
      we'll see, it<br>
      does come with some additional constraints.<br>
      <br>
      ### Wrapping an existing API<br>
      <br>
      Nearly every library has methods (sometimes sets of methods) that
      are patterns<br>
      in disguise, such as the pair of methods `isArray` and
      `getComponentType` in<br>
      `Class`, or the `Matcher` helper type in `java.util.regex`. 
      Library maintainers<br>
      will likely want to wrap (or replace) these with real patterns, so
      these can<br>
      participate more effectively in conditional contexts, and in some
      cases,<br>
      highlight their duality with factory methods.<br>
      <br>
      Matching a string against a `j.u.r.Pattern` regular expression has
      all the same<br>
      elements as a pattern, just with an ad-hoc API (and one that I
      have to look up<br>
      every time).  But we can fairly easily wrap a true pattern around
      the existing<br>
      API.  To match against a `Pattern` today, we pass the match
      candidate to<br>
      `Pattern::matcher`, which returns a `Matcher` with accessors
      `Matcher::matches`<br>
      (did it match) and `Matcher::group` (conditionally extract a
      particular capture<br>
      group.)  If we want to wrap this with a pattern called
      `regexMatch`:<br>
      <br>
      ```<br>
      pattern(String that) regexMatch(String... groups) {<br>
          Matcher m = this.matcher(that);<br>
          if (m.matches())<br>
              matches Pattern.regexMatch(IntStream.range(1,
      m.groupCount())<br>
                                                  .map(Matcher::group)<br>
                                                 
      .toArray(String[]::new));<br>
          // whole lotta matchin' goin' on<br>
      }<br>
      ```<br>
      <br>
      This says that a `j.u.r.Pattern` has an instance pattern called
      `regex`, whose<br>
      match candidate is `String`, and which binds a varargs of `String`
      corresponding<br>
      to the capture groups.  The implementation simply delegates to the
      existing<br>
      `j.u.r.Matcher` API.  This means that `j.u.r.Pattern` becomes a
      sort of "pattern<br>
      object", and we can use it as a receiver at the use site: <br>
      <br>
      ```<br>
      static Pattern As = Pattern.compile("(a*)");<br>
      static Pattern Bs = Pattern.compile("(b*)");<br>
      ...<br>
      switch (string) { <br>
          case As.regexMatch(var as): ...<br>
          case Bs.regexMatch(var bs): ...<br>
          ...<br>
      }<br>
      ```<br>
      <br>
      ### Odds and ends<br>
      <br>
      There are a number of loose ends here.  We could choose other
      names for the<br>
      match-success and match-fail operations, including trying to reuse
      `break` or<br>
      `yield`.  But, this reuse is tricky; it must be very clear whether
      a given form<br>
      of abrupt completion means "success" or "failure", because in the
      case of<br>
      patterns with no bindings, we will have no other syntactic cues to
      help<br>
      disambiguate.  (I think having a single `matches`, with implicit
      failure and<br>
      `return` meaning failure, is the sweet spot here.)<br>
      <br>
      Another question is whether the binding list introduces
      corresponding variables<br>
      into the scope of the body.  For imperative, the answer is "surely
      yes"; for<br>
      functional, the answer is "maybe" (unless we want to do the trick
      where we<br>
      derive imperative from functional, in which case the answer is
      "yes" again.)<br>
      <br>
      If the binding list does not correspond to variables in the body,
      this may be<br>
      initially discomforting; because they do not declare program
      elements, they may<br>
      feel that they are left "dangling".  But even if they are not
      declaring<br>
      _program_ elements, they are still declaring _API_ elements
      (similar to the<br>
      return type of a method.)  We will want to provide Javadoc on the
      bindings, just<br>
      like with parameters; we will want to match up binding names in
      deconstructors<br>
      with parameter names in constructors; we may even someday want to
      support<br>
      by-name binding at the use site (e.g., `case Foo(a: var a)`).  The
      names are<br>
      needed for all of these, just not for the body. Names still
      matter.  My take<br>
      here is that this is a transient "different is scary" reaction,
      one that we<br>
      would get over quickly.<br>
      <br>
      A final question is whether we should consider unqualified names
      as implicitly<br>
      qualified by `that` (and also `this`, for instance patterns, with
      some conflict<br>
      resolution).  Users will probably grow tired of typing `that.` all
      the time, and most of the time, the unqualified use is perfectly
      readable.<br>
      <br>
      ## Exhaustiveness <br>
      <br>
      There is one last syntax question in front of us: how to indicate
      that a set of<br>
      patterns are (claimed to be) exhaustive on a given match candidate
      type.  We see<br>
      this with `Optional::of` and `Optional::empty`; it would be sad if
      the compiler<br>
      did not realize that these two patterns together were exhaustive
      on `Optional`.<br>
      This is not a feature that will be used often, but not having it
      at all will be<br>
      a repeated irritant.<br>
      <br>
      The best I've come up with is to call these `case` patterns, where
      a set of<br>
      `case` patterns for a given match candidate type in a given class
      are asserted<br>
      to be an exhaustive set:<br>
      <br>
      ```<br>
      class Optional<T> { <br>
          static<T> Optional<T> of(T t) { ... }<br>
          static<T> Optional<T> empty() { ... }<br>
      <br>
          static<T> case pattern of(T t) for Optional<T> {
      ... }<br>
          static<T> case pattern empty() for Optional<T> {
      ... }<br>
      }<br>
      ```<br>
      <br>
      Because they may not be truly exhaustive, `switch` constructs will
      have to back<br>
      up the static assumption of exhaustiveness with a dynamic check,
      as we do for<br>
      other sets of exhaustive patterns that may have remainder.<br>
      <br>
      I've experimented with variants of `sealed` but it felt more
      forced, so this is<br>
      the best I've come up with.<br>
      <br>
      ## Example: patterns delegating to other patterns<br>
      <br>
      Pattern implementations must compose.  Just as a subclass
      constructor delegates<br>
      to a superclass constructor, the same should be true for
      deconstructors.<br>
      Here's a typical superclass-subclass pair: <br>
      <br>
      ```<br>
      class A { <br>
          private final int a;<br>
      <br>
          public A(int a) { this.a = a; }<br>
          public pattern A(int a) { matches A(that.a); }<br>
      }<br>
      <br>
      class B extends A { <br>
          private final int b;<br>
      <br>
          public B(int a, int b) { <br>
              super(a);<br>
              this.b = b; <br>
          }<br>
      <br>
          // Imperative style <br>
          public pattern B(int a, int b) {<br>
              if (that instanceof super(var aa)) {<br>
                  a = aa;<br>
                  b = that.b;<br>
                  matches B;<br>
              }<br>
          }<br>
      <br>
          // Functional style<br>
          public pattern B(int a, int b) {<br>
              if (that instanceof super(var a)) <br>
                  matches B(a, b);<br>
          }<br>
      }<br>
      ```<br>
      <br>
      (Ignore the flow analysis and totality for the time being; we'll
      come back to<br>
      this in a separate document.)<br>
      <br>
      The first thing that jumps out at us is that, in the imperative
      version, we had<br>
      to create a "garbage" variable `aa` to receive the binding,
      because `a` was<br>
      already in scope, and then we have to copy the garbage variable
      into the real<br>
      binding variable. Users will surely balk at this, and rightly so. 
      In the<br>
      functional version (depending on the choices from "Odds and Ends")
      we are free<br>
      to use the more natural name and avoid the roundabout locution.<br>
      <br>
      We might be tempted to fix the "garbage variable" problem by
      inventing another<br>
      sub-feature: the ability to use an existing variable as the target
      of a binding,<br>
      such as:<br>
      <br>
      ```<br>
      pattern Point(int a, int b) {<br>
          if (this instanceof A(__bind a))<br>
              b = this.b;<br>
      }<br>
      ```<br>
      <br>
      But, I think the language is stronger without this feature, for
      two reasons.<br>
      First, having to reason about whether a pattern match introduces a
      new binding<br>
      or assigns to an existing variables is additional cognitive load
      for users to<br>
      reason about, and second, having assignment to locals happening
      through<br>
      something other than assignment introduces additional complexity
      in finding<br>
      where a variable is modified.  While we can argue about the
      general utility of<br>
      this feature, bringing it in just to solve the garbage-variable
      problem is<br>
      particularly unattractive.  <br>
      <br>
      ## Pattern lambdas<br>
      <br>
      One final consideration is is that patterns may also have a lambda
      form.  Given<br>
      a single-abstract-pattern (SAP) interface:<br>
      <br>
      ```<br>
      interface Converter<T,U> { <br>
          pattern(T t) convert(U u);<br>
      }<br>
      ```<br>
      <br>
      one can implement such a pattern with a lambda. Such a lambda has
      one parameter<br>
      (the match candidate), and its body looks like the body of a
      declared pattern:<br>
      <br>
      ```<br>
      Converter<Integer, Short> c = <br>
          i -> { <br>
              if (i >= Short.MIN_VALUE && i <=
      Short.MAX_VALUE)<br>
                  matches Converter.convert((short) i);<br>
          };<br>
      ```<br>
      <br>
      Because the bindings of the pattern lambda are defined in the
      interface, not in<br>
      the lambda, this is one more reason not to like the imperative
      version: it is<br>
      brittle, and alpha-renaming bindings in the interface would be a<br>
      source-incompatible change.<br>
      <br>
      ## Example gallery<br>
      <br>
      Here's all the pattern examples so far, and a few more, using the
      suggested<br>
      style (functional, implicit fail, implicit `that`-qualification):<br>
      <br>
      ```<br>
      // Point dtor <br>
      pattern Point(int x, int y) {<br>
          matches Point(x, y);<br>
      }<br>
      <br>
      // Optional -- static patterns for Optional::of, Optional::empty<br>
      static<T> case pattern(Optional<T> that) of(T t) { <br>
          if (isPresent())<br>
              matches of(t);<br>
      }<br>
      <br>
      static<T> case pattern(Optional<T> that) empty() { <br>
          if (!isPresent())<br>
              matches empty();<br>
      }<br>
      <br>
      // Class -- instance pattern for arrayClass (match candidate type
      inferred)<br>
      pattern arrayClass(Class<?> componentType) { <br>
          if (that.isArray())<br>
              matches arrayClass(that.getComponentType());<br>
      }<br>
      <br>
      // regular expression -- instance pattern in j.u.r.Pattern<br>
      pattern(String that) regexMatch(String... groups) {<br>
          Matcher m = matcher(that);<br>
          if (m.matches())<br>
              matches Pattern.regexMatch(IntStream.range(1,
      m.groupCount())<br>
                                                  .map(Matcher::group)<br>
                                                 
      .toArray(String[]::new));<br>
      }<br>
      <br>
      // power of two (somewhere)<br>
      static pattern(int that) powerOfTwo(int exp) {<br>
          int exp = 0;<br>
      <br>
          if (that < 1)<br>
              return;<br>
      <br>
          while (that > 1) {<br>
              if (that % 2 == 0) {<br>
                  that /= 2;<br>
                  exp++;<br>
              }<br>
              else<br>
                  return;<br>
          }<br>
          matches powerOfTwo(exp);<br>
      }<br>
      ```<br>
      <br>
      ## Closing thoughts<br>
      <br>
      I came out of this exploration with very different conclusions
      than I expected<br>
      when going in.  At first, the "inverse" syntax seemed stilted, but
      over time it<br>
      started to seem more obvious.  Similarly, I went in expecting to
      prefer the<br>
      imperative approach for the body, but over time, started to warm
      to the<br>
      functional approach, and eventually concluded it was basically a
      forced move if<br>
      we want to support more than just deconstructors.  And I started
      out skeptical<br>
      of "implicit fail", but after writing a few dozen patterns with
      it, going back<br>
      to fully explicit felt painful.  All of this is to say, you should
      hold your<br>
      initial opinions at arm's length, and give the alternatives a
      chance to sink in.<br>
      <br>
      For most _conditional_ patterns (and conditionality is at the
      heart of pattern<br>
      matching), the functional approach cleanly highlights both the
      match predicate<br>
      and the flow of values, and is considerably less fussy than the
      imperative<br>
      approach in the same situation; `Optional::of`,
      `Class::arrayClass`, and `regex`<br>
      look great here, much better than the would with imperative.  None
      of these<br>
      illustrate delegation, but in the presence of delegation, the gap
      gets even<br>
      wider.<br>
      <br>
    </font>
  </div>

</blockquote></div>