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