<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <blockquote type="cite" cite="mid:CANSoFxtysPkbbaetD0M5GStp_wdWFVhUPc0ig_CKCbS556dKJA@mail.gmail.com">
      <div dir="ltr">
        <div class="gmail_quote gmail_quote_container">
          <div>That's a good requirement, and I agree that identity
            equality is wrong for records and carriers, but there was
            another way we could have achieved this requirement, i.e, by
            using value equality (i.e., using == on each component)
            instead of recursive equality (using equals() on each
            component) or identity equality (using == on this &
            that).</div>
          <div><br>
          </div>
          <div>Asking in another way, how would you describe the
            conceptual distinction between a record and a value class?</div>
        </div>
      </div>
    </blockquote>
    <br>
    There is a lot of overlap; I would expect that many records/carriers
    can be value records/carriers, and many value classes can be
    carriers/records -- but neither subsumes the other.  <br>
    <br>
    The essence of value-ness is the lack of identity (and all that
    implies -- no mutability, no layout polymorphism, no monitor, no
    self-recursion, etc.)  The main semantic implication is that this
    changes the meaning of `==` (and hence the default Object::equals)
    to be state-based.  But this is not as broadly useful as it sounds;
    once you get away from the things that are truly "value all the way
    down" (numbers, dates, etc) and start to talk about value classes
    whose fields are identity objects (including, sadly, strings), then
    `==` reasserts its limitations.  This is imperfect but it is the
    least imperfect thing we can do given the historical meaning of `==`
    and the gazillions of lines of code that have been written around
    that meaning.  So while values get a "better" `==` out of the box,
    `==` remains a low-level mechanism best left to low-level code.  <br>
    <br>
    The essence of record-ness is alignment of external and internal
    representations.  (This assumes a record _has_ an external
    representation, the semantics of which are being subsumed by
    carriers.)  For types that "just" represent possibly-constrained
    products, records are an ideal choice.  <br>
    <br>
    (To complete the story, the essence of carrier-ness is that there is
    a state description, which describes the "external representation",
    and that external representation is complete, canonical, and
    nominal.  This puts construction, deconstruction, and reconstruction
    on solid ground.)<br>
    <br>
    Each of value-ness / record-ness means giving something up and
    getting something in return.  If you are willing to give up both set
    of things, you get both sets of benefits.  Many classes will fit
    into that story, such as <br>
    <br>
        value record Rational(int num, int denom) { ... }<br>
        value record DateTime(Date date, Time time) { ... } // where
    Date and Time are values<br>
        value record Complex(double real, double imag) { ... }<br>
    <br>
    (Whether or not Rational overrides equals() depends on whether the
    constructor normalizes to lowest terms; if the constructor reduces
    preemptively, then `==` is all that is needed and we can inherit
    Object::equals, but either way we would expect `new Rational(2,4)`
    and `new Rational(3,6)` to be equals.)  <br>
    <br>
    The introduction of carriers means many of the properties that used
    to be properties of records are now properties of carriers
    (deconstruction patterns, the take-it-apart-and-put-it-together
    guarantee, etc); the difference between records and carriers (as
    proposed) is that records are a _particular example_ of carriers,
    but all the semantic guarantees come from carrier-ness.  Which makes
    your question: what is the difference between values and carriers?<br>
    <br>
    The difference is:<br>
     - Carriers are tightly constrained to a specific relationship
    between their put-it-together behaviors (constructors) and their
    take-it-apart behaviors (accessors, deconstruction), that is
    consistent with equality, but they are allowed to use identity and
    all the things it implies.  Carriers get semantic benefits (e.g.
    reconstruction) in exchange for this deal.<br>
     - Values can be cagier about their implementation (they can be
    complete black boxes), but are constrained to not use identity and
    all the things it implies.  Values get runtime benefits (e.g.,
    flattening) in exchange for this deal.<br>
    <br>
    The deals are not mutually exclusive.<br>
    <br>
    <br>
  </body>
</html>