Data Oriented Programming, Beyond Records
Brian Goetz
brian.goetz at oracle.com
Wed Jan 21 21:29:53 UTC 2026
> 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).
>
> Asking in another way, how would you describe the conceptual
> distinction between a record and a value class?
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.
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.
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.
(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.)
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
value record Rational(int num, int denom) { ... }
value record DateTime(Date date, Time time) { ... } // where Date
and Time are values
value record Complex(double real, double imag) { ... }
(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.)
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?
The difference is:
- 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.
- 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.
The deals are not mutually exclusive.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20260121/4a4d1c51/attachment-0001.htm>
More information about the amber-spec-experts
mailing list