Data Oriented Programming, Beyond Records
forax at univ-mlv.fr
forax at univ-mlv.fr
Wed Jan 21 17:36:40 UTC 2026
> From: "Brian Goetz" <brian.goetz at oracle.com>
> To: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "Viktor Klang" <viktor.klang at oracle.com>, "amber-spec-experts"
> <amber-spec-experts at openjdk.java.net>
> Sent: Tuesday, January 20, 2026 10:43:56 PM
> Subject: Re: Data Oriented Programming, Beyond Records
> Fair point that we should be more precise about this. For the record, here is
> how record equality currently works:
> BRIEF HISTORICAL DIGRESSION
> The `equals` and `hashCode` implementations are indeed derived from the fields,
> not the accessors. To super-simplify the discussion (not to reopen it):
> - 99.9% of the time, the user will not provide explicit accessors, and in these
> cases, it makes no difference.
> - When a user does provide an explicit accessor, it will almost always be to
> perform a defensive copy.
> - If the thing being copied is a collection, the answer makes no difference
> (Collection::equals is contents-based) and using the accessor is much^2 more
> expensive
> - If the thing being copied is an array, comparing the copy would use spurious
> identity and would be semnatically wrong -- so in this case you _always_ have
> to override equals anyway, so in this case it makes no difference
> While this may seem like it is just guessing what users will do, this is
> actually rooted in the spec of Record::equals:
>> Indicates whether some other object is "equal to" this one. In addition to the
>> general contract of Object.equals, record classes must further obey the
>> invariant that when a record instance is "copied" by passing the result of the
>> record component accessor methods to the canonical constructor, as follows:
>> R copy = new R(r.c1(), r.c2(), ..., r.cn());
> So summarizing the past decision: it should never make a difference semantically
> whether we use the fields or the accessors. Using the accessors is more
> formally correct, but in some cases, doing so would be dramatically more
> expensive without any benefit to the user. So it seemed an acceptably pragmatic
> choice to use the fields rather than accessors.
> END DIGRESSION
> Now, the question we should be discussing is: how should this implementation
> reality map to the goal of "records are degenerate carriers"?
The other solution seems to allow a carrier class to not be restricted to only describe data so like a record equals/hashCode/toString are derived from the fields that define a component.
The carrier class feature:
A carrier class is a class that define "virtual" components
- the accessors must be implemented or declared abstract
- the canonical constructor must be implemented if the class is concrete
- the record pattern works using accessors.
A carrier class is not restricted to be a data class (so no equals/hashCode/toString), it can represent any class that can be constructed/deconstructed as several virtual components.
The component field feature:
A field can be declared as "component", i.e. implementing one of the virtual component
- the field is automatically strict
- the accessor corresponding to the field can be derived (if not @Override)
- if at least one of the field is declared as component, equals/hashCode/toString can be derived
- if at least one of the field is declared as component, the compact constructor syntax is available and inside it, all the fields marked as component are initialized automatically
- if all virtual components have an associated component field, the canonical constructor can be derived
regards,
Rémi
> On 1/20/2026 1:35 PM, [ mailto:forax at univ-mlv.fr | forax at univ-mlv.fr ] wrote:
>>> From: "Brian Goetz" [ mailto:brian.goetz at oracle.com | <brian.goetz at oracle.com> ]
>>> To: "Remi Forax" [ mailto:forax at univ-mlv.fr | <forax at univ-mlv.fr> ]
>>> Cc: "Viktor Klang" [ mailto:viktor.klang at oracle.com | <viktor.klang at oracle.com>
>>> ] , "amber-spec-experts" [ mailto:amber-spec-experts at openjdk.java.net |
>>> <amber-spec-experts at openjdk.java.net> ]
>>> Sent: Tuesday, January 20, 2026 4:28:14 PM
>>> Subject: Re: Data Oriented Programming, Beyond Records
>>>>>> The modifier "component" is too close to the "property" modifier I wanted to
>>>>>> include years ago, it's just to sugary for its own good.
>>>>> You know the rule; mention syntax and you forfeit the right to more substantial
>>>>> comments....
>>>> I'm talking about the semantics, especially the fact that equals/hashCode and
>>>> toString() are derived from.
>>> Except that equals/hashCode have nothing to do with the "component" modifier _at
>>> all_. They are derived from the _state description_, in terms of the
>>> _accessors_, whose existence is implied directly by the _state description_.
>> I do not think you can do that, because it means that a record is not a carrier
>> class.
>> Do you agree that equals() and hashCode() of a record are not derived from the
>> accessors ?
>> regards,
>> Rémi
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20260121/64eb0f94/attachment.htm>
More information about the amber-spec-experts
mailing list