<div dir="auto">I know that we are not discussing syntax here, but one thing about carrier classes state declaration that strikes me the most is that essentially declaring private final component field is more or less the duplication of it's signature type declaration and name.<div dir="auto"><br></div><div dir="auto">I actually believe that private final component fields will be by far the most popular case for carrier classes, so I am wondering if this is the part of internal state declaration that can also be elided by default, but gradually overridable (i.e. component declared in "header" as String x can either have auto-generated private final component field, have explicitly declared (for the sake of changing modifiers) component field String x, or completely different internal representation with no direct mapping).</div><div dir="auto"><br></div><div dir="auto">One thing that possibly bothers me is the fact that, most likely, this will take reader quite some time to figure out (at least without ide help), which degree of implicitness each components has, so maybe there is a worth in making people say something like class Point(component int x, ...) to be more explicit about autogeneration case</div><div dir="auto"><br></div><div dir="auto">Best regards</div></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Tue, Jan 13, 2026, 23:53 Brian Goetz <<a href="mailto:brian.goetz@oracle.com">brian.goetz@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><u></u>

  
  <div>
    <font size="4" face="monospace">Here's a snapshot of where my head
      is at with respect to extending the record goodies (including
      pattern matching) to a broader range of classes, deconstructors
      for classes and interfaces, and compatible evolution of records. 
      Hopefully this will unblock quite a few things.<br>
      <br>
      As usual, let's discuss concepts and directions rather than
      syntax.  <br>
      <br>
      <br>
      <br>
      # Data-oriented Programming for Java: Beyond records<br>
      <br>
      Everyone loves records; they allow us to create shallowly
      immutable data holder<br>
      classes -- which we can think of as "nominal tuples" -- derived
      from a concise<br>
      state description, and to destructure records through pattern
      matching.  But<br>
      records have strict constraints, and not all data holder classes
      fit into the<br>
      restrictions of records.  Maybe they have some mutable state, or
      derived or<br>
      cached state that is not part of the state description, or their
      representation<br>
      and their API do not match up exactly, or they need to break up
      their state<br>
      across a hierarchy.  In these classes, even though they may also
      be “data<br>
      holders”, the user experience is like falling off a cliff.  Even a
      small<br>
      deviation from the record ideal means one has to go back to a
      blank slate and<br>
      write explicit constructor declarations, accessor method
      declarations, and<br>
      Object method implementations -- and give up on destructuring
      through pattern<br>
      matching.  <br>
      <br>
      Since the start of the design process for records, we’ve kept in
      mind the goal<br>
      of enabling a broader range of classes to gain access to the
      "record goodies":<br>
      reduced declaration burden, participating in destructuring, and
      soon,<br>
      [reconstruction](<a href="https://openjdk.org/jeps/468" target="_blank" rel="noreferrer">https://openjdk.org/jeps/468</a>). During the design
      of records, we<br>
      also explored a number of weaker semantic models that would allow
      for greater<br>
      flexibility. While at the time they all failed to live up to the
      goals _for<br>
      records_, there is a weaker set of semantic constraints we can
      impose that<br>
      allows for more flexibility and still enables the features we
      want, along with<br>
      some degree of syntactic concision that is commensurate with the
      distance from<br>
      the record-ideal, without fall-off-the-cliff behaviors.  <br>
      <br>
      Records, sealed classes, and destructuring with record patterns
      constitute the<br>
      first feature arc of "data-oriented programming" for Java.  After
      considering<br>
      numerous design ideas, we're now ready to move forward with the
      next "data<br>
      oriented programming" feature arc: _carrier classes_ (and
      interfaces.)<br>
      <br>
      ## Beyond record patterns<br>
      <br>
      Record patterns allow a record instance to be destructured into
      its components.<br>
      Record patterns can be used in `instanceof` and `switch`, and when
      a record<br>
      pattern is also exhaustive, will be usable in the upcoming
      [_pattern assignment<br>
statement_](<a href="https://mail.openjdk.org/pipermail/amber-spec-experts/2026-January/004306.html" target="_blank" rel="noreferrer">https://mail.openjdk.org/pipermail/amber-spec-experts/2026-January/004306.html</a>)
      feature.  <br>
      <br>
      In exploring the question "how will classes be able to participate
      in the same<br>
      sort of destructuring as records", we had initially focused on a
      new form of<br>
      declaration in a class -- a "deconstructor" -- that operated as a
      constructor in<br>
      reverse. Just as a constructor takes component values and produces
      an aggregate<br>
      instance, a deconstructor would take an aggregate instance and
      recover its<br>
      component values.  <br>
      <br>
      But as this exploration played out, the more interesting question
      turned out to<br>
      be: which classes are suitable for destructuring in the first
      place? And the<br>
      answer to that question led us to a different approach for
      expressing<br>
      deconstruction.  The classes that are suitable for destructuring
      are those that,<br>
      like records, are little more than carriers for a specific tuple
      of data. This<br>
      is not just a thing that a class _has_, like a constructor or
      method, but<br>
      something a class _is_.  And as such, it makes more sense to
      describe<br>
      deconstruction as a top-level property of a class.  This, in turn,
      leads to a<br>
      number of simplifications.  <br>
      <br>
      ## The power of the state description<br>
      <br>
      Records are a semantic feature; they are only incidentally
      concise.  But they<br>
      _are_ concise; when we declare a record<br>
      <br>
          record Point(int x, int y) { ... }<br>
      <br>
      we automatically get a sensible API (canonical constructor,
      deconstruction<br>
      pattern, accessor methods for each component) and implementation
      (fields,<br>
      constructor, accessor methods, Object methods.)  We can explicitly
      specify most<br>
      of these (except the fields) if we like, but most of the time we
      don't have to,<br>
      because the default is exactly what we want.<br>
      <br>
      A record is a shallowly-immutable, final class whose API and
      representation are<br>
      _completely defined_ by its _state description_.  (The slogan for
      records is<br>
      "the state, the whole state, and nothing but the state.")  The
      state description<br>
      is the ordered list of _record components_ declared in the
      record's header.  A<br>
      component is more than a mere field or accessor method; it is an
      API element on<br>
      its own, describing a state element that instances of the class
      have.  <br>
      <br>
      The state description of a record has several desirable
      properties: <br>
      <br>
       - The components in the order specified, are the _canonical_
      description of the<br>
         record's state.<br>
       - The components are the _complete_ description of the record’s
      state.  <br>
       - The components are _nominal_; their names are a committed part
      of the<br>
         record's API.  <br>
      <br>
      Records derive their benefits from making two commitments:<br>
      <br>
       - The _external_ commitment that the data-access API of a record
      (constructor,<br>
         deconstruction pattern, and component accessor methods) is
      defined by the<br>
         state description.  <br>
       - The _internal_ commitments that the _representation_ of the
      record (its<br>
         fields) is also completely defined by the state description.<br>
      <br>
      These semantic properties are what enable us to derive almost
      everything about<br>
      records.  We can derive the API of the canonical constructor
      because the state<br>
      description is canonical.  We can derive the API for the component
      accessor<br>
      methods because the state description is nominal.  And we can
      derive a<br>
      deconstruction pattern from the accessor methods because the state
      description<br>
      is complete (along with sensible implementations for the
      state-related `Object`<br>
      methods.)<br>
      <br>
      The internal commitment that the state description is also the
      representation<br>
      allows us to completely derive the rest of the implementation. 
      Records get a<br>
      (private, final) field for each component, but more importantly,
      there is a<br>
      clear mapping between these fields and their corresponding
      components, which is<br>
      what allows us to derive the canonical constructor and accessor
      method<br>
      implementations.  <br>
      <br>
      Records can additionally declare a _compact constructor_ that
      allows us to elide<br>
      the boilerplate aspects of record constructors -- the argument
      list and field<br>
      assignments -- and just specify the code that is _not_
      mechanically derivable.<br>
      This is more concise, less error-prone, and easier to read:<br>
      <br>
          record Rational(int num, int denom) { <br>
              Rational { <br>
                  if (denom == 0)<br>
                      throw new IllegalArgumentException("denominator
      cannot be zero");<br>
              }<br>
          }<br>
      <br>
      is shorthand for the more explicit<br>
      <br>
          record Rational(int num, int denom) { <br>
              Rational(int num, int denom) { <br>
                  if (denom == 0)<br>
                      throw new IllegalArgumentException("denominator
      cannot be zero");<br>
                  this.num = num;<br>
                  this.denom = denom;<br>
              }<br>
          }<br>
      <br>
      While compact constructors are pleasantly concise, the more
      important benefit is<br>
      that by eliminating the mechanically derivable code, the "more
      interesting" code<br>
      comes to the fore.  <br>
      <br>
      Looking ahead, the state description is a gift that keeps on
      giving.  These<br>
      semantic commitments are enablers for a number of potential future
      language and<br>
      library features for managing object lifecycle, such as: <br>
      <br>
       - [Reconstruction](<a href="https://openjdk.org/jeps/468" target="_blank" rel="noreferrer">https://openjdk.org/jeps/468</a>) of record
      instances, allowing<br>
         the appearance of controlled mutation of record state.<br>
       - Automatic marshalling and unmarshalling of record instances.<br>
       - Instantiating or destructuring record instances identifying
      components<br>
         nominally rather than positionally.<br>
      <br>
      ### Reconstruction<br>
      <br>
      JEP 468 proposes a mechanism by which a new record instance can be
      derived from<br>
      an existing one using syntax that is evocative of direct mutation,
      via a `with`<br>
      expression: <br>
      <br>
          record Complex(double re, double im) { }<br>
          Complex c = ...<br>
          Complex cConjugate = c with { im = -im; }; <br>
      <br>
      The block on the right side of `with` can contain any Java
      statements, not just<br>
      assignments.  It is enhanced with mutable variables (_component
      variables_) for<br>
      each component of the record, initialized to the value of that
      component in the<br>
      record instance on the left, the block is executed, and a new
      record instance is<br>
      created whose component values are the ending values of the
      component variables.  <br>
      <br>
      A reconstruction expression implicitly destructures the record
      instance using<br>
      the canonical deconstruction pattern, executes the block in a
      scope enhanced<br>
      with the component variables, and then creates a new record using
      the canonical<br>
      constructor.  Invariant checking is centralized in the canonical
      constructor, so<br>
      if the new state is not valid, the reconstruction will fail.  JEP
      468 has been<br>
      "on hold" for a while, primarily because we were waiting for
      sufficient<br>
      confidence that there was a path to extending it to suitable
      classes before<br>
      committing to it for records.  The ideal path would be for those
      classes to also<br>
      support a notion of canonical constructor and deconstruction
      pattern.  <br>
      <br>
      Careful readers will note a similarity between the transformation
      block of a<br>
      `with` expression and the body of a compact constructor.  In both
      cases, the<br>
      block is "preloaded" with a set of component variables,
      initialized to suitable<br>
      starting values, the block can mutate those variables as desired,
      and upon<br>
      normal completion of the block, those variables are passed to a
      canonical<br>
      constructor to produce the final result.  The main difference is
      where the<br>
      starting values come from; for a compact constructor, it is from
      the constructor<br>
      parameters, and for a reconstruction expression, it is from the
      canonical<br>
      deconstruction pattern of the source record to the left of `with`.<br>
       <br>
      ### Breaking down the cliff<br>
      <br>
      Records make a strong semantic commitment to derive both their API
      and<br>
      representation from the state description, and in return get a lot
      of help from<br>
      the language.  We can now turn our attention to smoothing out "the
      cliff" --<br>
      identifying weaker semantic commitments that classes can make that
      would still<br>
      allow classes to get _some_ help from the language.  And ideally,
      the amount of<br>
      help you give up would be proportional to the degree of deviation
      from the<br>
      record ideal.<br>
      <br>
      With records, we got a lot of mileage out of having a complete,
      canonical,<br>
      nominal state description.  Where the record contract is sometimes
      too<br>
      constraining is the _implementation_ contract that the
      representation aligns<br>
      exactly with the state description, that the class is final, that
      the fields are<br>
      final, and that the class may not extend anything but `Record`.  <br>
      <br>
      Our path here takes one step back and one step forward: keeping
      the external<br>
      commitment to the state description, but dropping the internal
      commitment that<br>
      the state description _is_ the representation -- and then _adding
      back_ a simple<br>
      mechanism for mapping fields representing components back to their
      corresponding<br>
      components, where practical.  (With records, because we derive the<br>
      representation from the state description, this mapping can be
      safely inferred.)  <br>
      <br>
      As a thought experiment, imagine a class that makes the external
      commitment to a<br>
      state description -- that the state description is a complete,
      canonical,<br>
      nominal description of its state -- but is on its own to provide
      its<br>
      representation.  What can we do for such a class?  Quite a bit,
      actually.  For<br>
      all the same reasons we can for records, we can derive the API
      requirement for a<br>
      canonical constructor and component accessor methods.  From there,
      we can derive<br>
      both the requirement for a canonical deconstruction pattern, and
      also the<br>
      implementation of the deconstruction pattern (as it is implemented
      in terms of<br>
      the accessor methods). And since the state description is
      complete, we can<br>
      further derive sensible default implementations of the Object
      methods `equals`,<br>
      `hashCode`, and `toString` in terms of the accessor methods as
      well. And given<br>
      that there is a canonical constructor and deconstruction pattern,
      it can also<br>
      participate in reconstruction.  The author would just have to
      provide the<br>
      fields, accessor methods, and canonical constructor.  This is good
      progress, but<br>
      we'd like to do better.<br>
      <br>
      What enables us to derive the rest of the implementation for
      records (fields,<br>
      constructor, accessor methods, and Object methods) is the
      knowledge of how the<br>
      representation maps to the state description.  Records commit to
      their state<br>
      description _being_ the representation, so is is a short leap from
      there to a<br>
      complete implementation.  <br>
      <br>
      To make this more concrete, let's look at a typical "almost
      record" class, a<br>
      carrier for the state description `(int x, int y,
      Optional<String> s)` but which<br>
      has made the representation choice to internally store `s` as a
      nullable<br>
      `String`.  <br>
      <br>
      ```<br>
      class AlmostRecord { <br>
          private final int x;<br>
          private final int y;<br>
          private final String s;                                 // *<br>
      <br>
          public AlmostRecord(int x, int y, Optional<String> s) { <br>
              this.x = x;<br>
              this.y = y;<br>
              this.s = s.orElse(null);                            // *<br>
          }<br>
      <br>
          public int x() { return x; }<br>
          public int y() { return y; }<br>
          public Optional<String> s() { <br>
              return Optional.ofNullable(s);                      // *<br>
          }<br>
      <br>
          public boolean equals(Object other) { ... }     // derived
      from x(), y(), s()<br>
          public int hashCode() { ... }                   //    "<br>
          public String toString() { ... }                //    "<br>
      }<br>
      ```<br>
      <br>
      The main differences between this class and the expansion of its
      record analogue<br>
      are the lines marked with a `*`; these are the ones that deal with
      the disparity<br>
      between the state description and the actual representation.  It
      would be nice<br>
      if the author of this class _only_ had to write the code that was
      different from<br>
      what we could derive for a record; not only would this be
      pleasantly concise,<br>
      but it would mean that all the code that _is_ there exists to
      capture the<br>
      differences between its representation and its API.  <br>
      <br>
      ## Carrier classes<br>
      <br>
      A _carrier class_ is a normal class declared with a state
      description.  As with<br>
      a record, the state description is a complete, canonical, nominal
      description of<br>
      the class's state.  In return, the language derives the same API
      constraints as<br>
      it does for records: canonical constructor, canonical
      deconstruction pattern,<br>
      and component accessor methods.<br>
      <br>
         class Point(int x, int y) {                // class, not
      record!<br>
             // explicitly declared representation<br>
      <br>
             ...<br>
      <br>
             // must have a constructor taking (int x, int y)<br>
             // must have accessors for x and y<br>
             // supports a deconstruction pattern yielding (int x, int
      y)<br>
         }<br>
      <br>
      Unlike a record, the language makes no assumptions about the
      object's<br>
      representation; the class author has to declare that just as with
      any other<br>
      class.  <br>
      <br>
      Saying the state description is "complete" means that it carries
      all the<br>
      “important” state of the class -- if we were to extract this state
      and recreate<br>
      the object, that should yield an “equivalent” instance.  As with
      records, this<br>
      can be captured by tying together the behavior of construction,
      accessors, and<br>
      equality:<br>
      <br>
      ```<br>
      Point p = ...<br>
      Point q = new Point(p.x(), p.y());<br>
      assert p.equals(q);<br>
      ```<br>
      <br>
      We can also derive _some_ implementation from the information we
      have so far; we<br>
      can derive sensible implementations of the `Object` methods
      (implemented in terms<br>
      of component accessor methods) and we can derive the canonical
      deconstruction<br>
      pattern (again in terms of the component accessor methods).  And
      from there, we<br>
      can derive support for reconstruction (`with` expressions.) 
      Unfortunately, we<br>
      cannot (yet) derive the bulk of the state-related implementation:
      the canonical<br>
      constructor and component accessor methods.  <br>
      <br>
      ### Component fields and accessor methods<br>
      <br>
      One of the most tedious aspects of data-holder classes is the
      accessor methods;<br>
      there are often many of them, and they are almost always pure
      boilerplate.  Even<br>
      though IDEs can reduce the writing burden by generating these for
      us, readers<br>
      still have to slog through a lot of low-information code -- just
      to learn that<br>
      they didn't actually need to slog through that code after all.  We
      can derive<br>
      the implementation of accessor methods for records because records
      make the<br>
      internal commitment that the components are all backed with
      individual fields<br>
      whose name and type align with the state description.  <br>
      <br>
      For a carrier class, we don't know whether _any_ of the components
      are directly<br>
      backed by a single field that aligns to the name or type of the
      component.  But<br>
      it is a pretty good bet that many carrier class components will do
      exactly this<br>
      for at least _some_ of their fields.  If we can tell the language
      that this<br>
      correspondence is not merely accidental, the language can do more
      for us.<br>
      <br>
      We do so by allowing suitable fields of a carrier class to be
      declared as<br>
      `component` fields.  (As usual at this stage, syntax is
      provisional, but not <br>
      currently a topic for discussion.)  A component field must have
      the same name<br>
      and type as a component of the current class (though it need not
      be `private` or<br>
      `final`, as record fields are.)  This signals that this field _is_
      the<br>
      representation for the corresponding component, and hence we can
      derive the<br>
      accessor method for this component as well.  <br>
      <br>
      ```<br>
      class Point(int x, int y) { <br>
          private /* mutable */ component int x;<br>
          private /* mutable */ component int y;<br>
      <br>
          // must have a canonical constructor, but (so far) must be
      explicit<br>
          public Point(int x, int y) { <br>
              this.x = x;<br>
              this.y = y;<br>
          }<br>
      <br>
          // derived implementations of accessors for x and y<br>
          // derived implementations of equals, hashCode, toString<br>
      }<br>
      ```<br>
      <br>
      This is getting better; the class author had to bring the
      representation and the<br>
      mapping from representation to components (in the form of the
      `component`<br>
      modifier), and the canonical constructor.  <br>
      <br>
      ### Compact constructors<br>
      <br>
      Just as we are able to derive the accessor method implementation
      if we are<br>
      given an explicit correspondence between a field and a component,
      we can do the<br>
      same for constructors.  For this, we build on the notion of
      _compact<br>
      constructors_ that was introduced for records.  <br>
      <br>
      As with a record, a compact constructor in a carrier class is a
      shorthand for a<br>
      canonical constructor, which has the same shape as the state
      description, but<br>
      which is freed of the responsibility of actually committing the
      ending value of<br>
      the component parameters to the fields.  The main difference is
      that for a<br>
      record, _all_ of the components are backed by a component field,
      whereas for a<br>
      carrier class, only some of them might be.  But we can generalize
      compact<br>
      constructors by freeing the author of the responsibility to
      initialize the<br>
      _component_ fields, while leaving them responsible for
      initializing the rest of<br>
      the fields.  In the limiting case where all components are backed
      by component<br>
      fields, and there is no other logic desired in the constructor,
      the compact<br>
      constructor may be elided.  <br>
      <br>
      For our mutable `Point` class, this means we can elide nearly
      everything, except<br>
      the field declarations themselves: <br>
      <br>
      ```<br>
      class Point(int x, int y) { <br>
          private /* mutable */ component int x;<br>
          private /* mutable */ component int y;<br>
      <br>
          // derived compact constructor<br>
          // derived accessors for x, y<br>
          // derived implementations of equals, hashCode, toString<br>
      }<br>
      ```<br>
      <br>
      We can think of this class as having an implicit empty compact
      constructor,<br>
      which in turn means that the component fields `x` and `y` are
      initialized from<br>
      their corresponding constructor parameters.  There are also
      implicitly derived<br>
      accessor methods for each component, and implementations of
      `Object` methods<br>
      based on the state description.  <br>
      <br>
      This is great for a class where all the components are backed by
      fields, but<br>
      what about our `AlmostRecord` class?  The story here is good as
      well; we can<br>
      derive the accessor methods for the components backed by component
      fields, and<br>
      we can elide the initialization of the component fields from the
      compact<br>
      constructor, meaning that we _only_ have to specify the code for
      the parts that<br>
      deviate from the "record ideal": <br>
      <br>
      ```<br>
      class AlmostRecord(int x, <br>
                         int y, <br>
                         Optional<String> s) { <br>
      <br>
          private final component int x;<br>
          private final component int y;<br>
          private final String s;<br>
      <br>
          public AlmostRecord { <br>
              this.s = s.orElse(null); <br>
              // x and y fields implicitly initialized<br>
          }<br>
      <br>
          public Optional<String> s() { <br>
              return Optional.ofNullable(s);  <br>
          }<br>
      <br>
          // derived implementation of x and y accessors<br>
          // derived implementation of equals, hashCode, toString<br>
      }<br>
      ```<br>
      <br>
      Because so many real-world almost-records differ from their record
      ideal in<br>
      minor ways, we expect to get a significant concision benefit for
      most carrier<br>
      classes, as we did for `AlmostRecord`.  As with records, if we
      want to<br>
      explicitly implement the constructor, accessor methods, or
      `Object` methods, we<br>
      are still free to do so. <br>
      <br>
      ### Derived state<br>
      <br>
      One of the most frequent complaints about records is the inability
      to derive<br>
      state from the components and cache it for fast retrieval.  With
      carrier<br>
      classes, this is simple: declare a non-component field for the
      derived quantity,<br>
      initialize it in the constructor, and provide an accessor: <br>
      <br>
      ```<br>
      class Point(int x, int y) { <br>
          private final component int x;<br>
          private final component int y;<br>
          private final double norm;<br>
      <br>
          Point { <br>
              norm = Math.hypot(x, y);<br>
          }<br>
      <br>
          public double norm() { return norm; }<br>
      <br>
          // derived implementation of x and y accessors<br>
          // derived implementation of equals, hashCode, toString<br>
      }<br>
      ```<br>
      <br>
      ### Deconstruction and reconstruction<br>
      <br>
      Like records, carrier classes automatically acquire deconstruction
      patterns that<br>
      match the canonical constructor, so we can destructure our `Point`
      class as if<br>
      it were a record: <br>
      <br>
          case Point(var x, var y): <br>
      <br>
      Because reconstruction (`with`) derives from a canonical
      constructor and<br>
      corresponding deconstruction pattern, when we support
      reconstruction of records,<br>
      we will also be able to do so for carrier classes:<br>
      <br>
          point = point with { x = 3; }<br>
      <br>
      ## Carrier interfaces<br>
      <br>
      A state description makes sense on interfaces as well.  It makes
      the statement<br>
      that the state description is a complete, canonical, nominal
      description of the<br>
      interface's state (subclasses are allowed to add additional
      state), and<br>
      accordingly, implementations must provide accessor methods for the
      components.<br>
      This enables such interfaces to participate in pattern matching:<br>
      <br>
      ```<br>
      interface Pair<T,U>(T first, U second) {<br>
          // implicit abstract accessors for first() and second()<br>
      }<br>
      <br>
      ...<br>
      <br>
      if (o instanceof Pair(var a, var b)) { ... }<br>
      ```<br>
      <br>
      Along with the upcoming feature for pattern assignment in
      foreach-loop headers,<br>
      if `Map.Entry` became a carrier interface (which it will), we
      would be able to<br>
      iterate a `Map` like:<br>
      <br>
          for (Map.Entry(var key, var val) : map.entrySet()) { ... }<br>
      <br>
      It is a common pattern in libraries to export an interface that is
      sealed to a<br>
      single private implementation.  In this pattern, the interface and<br>
      implementation can share a common state description: <br>
      <br>
      ```<br>
      public sealed interface Pair<T,U>(T first, U second) { }<br>
      <br>
      private record PairImpl<T, U>(T first, U second) implements
      Pair<T, U> { }<br>
      ```<br>
      <br>
      Compared to the old way of doing this, we get enhanced semantics,
      better type<br>
      checking, and more concision.  <br>
      <br>
      ### Extension<br>
      <br>
      The main obligation of a carrier class author is to ensure that
      the fundamental<br>
      claim -- that the state description is a complete, canonical,
      nominal<br>
      description of the object's state -- is actually true.  This does
      not rule out<br>
      having the representation of a carrier class spread out over a
      hierarchy, so<br>
      unlike records, carrier classes are not required to be final or
      concrete, nor<br>
      are they restricted in their extension.<br>
      <br>
      There are several cases that arise when carrier classes can
      participate in<br>
      extension:<br>
      <br>
       - A carrier class extends a non-carrier class;<br>
       - A non-carrier class extends a carrier class;<br>
       - A carrier class extends another carrier class, where all of the
      superclass<br>
         components are subsumed by the subclass state description; <br>
       - A carrier class extends another carrier class, but there are
      one or more<br>
         superclass components that are not subsumed by the subclass
      state<br>
         description.<br>
      <br>
      Extending a non-carrier class with a carrier class will usually be
      motiviated by<br>
      the desire to "wrap" a state description around an existing
      hierarchy which we<br>
      cannot or do not want to modify directly, but we wish to gain the
      benefits of<br>
      deconstruction and reconstruction.  Such an implementation would
      have to ensure<br>
      that the class actually conforms to the state description, and
      that the<br>
      canonical constructor and component accessors are implemented.  <br>
      <br>
      When one carrier class extends another, the more straightforward
      case is that it<br>
      simply adds new components to the state description of the
      superclass.  For<br>
      example, given our `Point` class:<br>
      <br>
      ```<br>
      class Point(int x, int y) { <br>
          component int x; <br>
          component int y;<br>
      <br>
          // everything else for free!<br>
      }<br>
      ```<br>
      <br>
      we can use this as the base class for a 3d point class: <br>
      <br>
      ```<br>
      class Point3d(int x, int y, int z) extends Point { <br>
          component int z;<br>
      <br>
          Point3d {<br>
              super(x, y);<br>
          }<br>
      }<br>
      ```<br>
      <br>
      In this case -- because the superclass components are all part of
      the subclass<br>
      state description -- we can actually omit the constructor as well,
      because we<br>
      can derive the association between subclass components and
      superclass<br>
      components, and thereby derive the needed super-constructor
      invocation.  So we<br>
      could actually write:<br>
      <br>
      ```<br>
      class Point3d(int x, int y, int z) extends Point { <br>
          component int z;<br>
      <br>
          // everything else for free!<br>
      }<br>
      ```<br>
      <br>
      One might think that we would need some marking on the `x` and `y`
      components of<br>
      `Point3d` to indicate that they map to the corresponding
      components of `Point`,<br>
      as we did for associating component fields with their
      corresponding components.<br>
      But in this case, we need no such marking, because there is no way
      that an `int<br>
      x` component of `Point` and an `int x` component of its subclass
      could possibly<br>
      refer to different things -- since they both are tied to the same
      `int x()`<br>
      accessor methods.  So we can safely infer which subclass
      components are managed<br>
      by superclasses, just by matching up their names and types.<br>
      <br>
      In the other carrier-to-carrier extension case, where one or more
      superclass<br>
      components are _not_ subsumed by the subclass state description,
      it is necessary<br>
      to provide an explicit `super` constructor call in the subclass
      constructor.  <br>
      <br>
      A carrier class may be also declared abstract; the main effect of
      this is that<br>
      we will not derive `Object` method implementations, instead
      leaving that for the<br>
      subclass to do.<br>
      <br>
      ### Abstract records<br>
      <br>
      This framework also gives us an opportunity to relax one of the
      restrictions on<br>
      records: that records can't extend anything other than
      `java.lang.Record`.  We<br>
      can also allow records to be declared `abstract`, and for records
      to extend<br>
      abstract records.  <br>
      <br>
      Just as with carrier classes that extend other carrier classes,
      there are two<br>
      cases: when the component list of the superclass is entirely
      contained within<br>
      that of the subclass, and when one or more superclass components
      are derived<br>
      from subclass components (or are constant), but are not components
      of the<br>
      subclass itself.  And just as with carrier classes, the main
      difference is<br>
      whether an explicit `super` call is required in the subclass
      constructor.  <br>
      <br>
      When a record extends an abstract record, any components of the
      subclass that<br>
      are also components of the superclass do not implicitly get
      component fields in<br>
      the subclass (because they are already in the superclass), and
      they inherit the<br>
      accessor methods from the superclass.  <br>
      <br>
      ### Records are carriers too<br>
      <br>
      With this framework in place, records can now be seen to be "just"
      carrier<br>
      classes that are implicitly final, extend `java.lang.Record`, that
      implicitly<br>
      have private final component fields for each component, and can
      have no other<br>
      fields.  <br>
      <br>
      ## Migration compatibility <br>
      <br>
      There will surely be some existing classes that would like to
      become carrier<br>
      classes.  This is a compatible migration as long as none of the
      mandated members<br>
      conflict with existing members of the class, and the class adheres
      to the<br>
      requirement that the state description is a complete, canonical,
      and nominal<br>
      description of the object state.  <br>
      <br>
      ### Compatible evolution of records and carrier classes<br>
      <br>
      To date, libraries have been reluctant to use records in public
      APIs because<br>
      of the difficulty of evolving them compatibly.  For a record: <br>
      <br>
      ```<br>
      record R(A a, B b) { }<br>
      ```<br>
      <br>
      that wants to evolve by adding new components:<br>
      <br>
      ```<br>
      record R(A a, B b, C c, D d) { }<br>
      ```<br>
      <br>
      we have several compatibility challenges to manage.  As long as we
      are only<br>
      adding and not removing/renaming, accessor method invocations will
      continue to<br>
      work. And existing constructor invocations can be allowed to
      continue work by<br>
      explicitly adding back a constructor that has the old shape: <br>
      <br>
      ```<br>
      record R(A a, B b, C c, D d) { <br>
      <br>
          // Explicit constructor for old shape required<br>
          public R(A a, B b) { <br>
              this(a, b, DEFAULT_C, DEFAULT_D);<br>
          }<br>
      <br>
      }<br>
      ```<br>
      <br>
      But, what can we do about existing uses of record _patterns_? 
      While the<br>
      translation of record patterns would make adding components
      binary-compatible,<br>
      it would not be source-compatible, and there is no way to
      explicitly add a<br>
      deconstruction pattern for the old shape as we did with the
      constructor.  <br>
      <br>
      We can take advantage of the simplification offered by there being
      _only_ the<br>
      canonical deconstruction pattern, and allow uses of deconstruction
      patterns to<br>
      supply nested patterns for any _prefix_ of the component list.  So
      for the<br>
      evolved record R: <br>
      <br>
          case R(P1, P2)<br>
      <br>
      would be interpreted as:<br>
      <br>
          case R(P1, P2, _, _)<br>
      <br>
      where `_` is the match-all pattern.  This means that one can
      compatibly evolve a<br>
      record by only adding new components at the end, and adding a
      suitable<br>
      constructor for compatibility with existing constructor
      invocations.<br>
      <br>
    </font>
  </div>

</blockquote></div>