Data Oriented Programming, Beyond Records

Brian Goetz brian.goetz at oracle.com
Sun Jan 18 01:00:19 UTC 2026


In reality, the deconstructor is not a method at all.

When we match:

     x instanceof R(P, Q)

we first ask `instanceof R`, and if that succeeds, we call the accessors 
for the first two components.  The accessors are instance methods, but 
the deconstructor is not embodied as a method.  This is true for 
carriers as well as for records.

On 1/17/2026 5:09 PM, forax at univ-mlv.fr wrote:
>
>
> ------------------------------------------------------------------------
>
>     *From: *"Viktor Klang" <viktor.klang at oracle.com>
>     *To: *"Remi Forax" <forax at univ-mlv.fr>, "Brian Goetz"
>     <brian.goetz at oracle.com>
>     *Cc: *"amber-spec-experts" <amber-spec-experts at openjdk.java.net>
>     *Sent: *Saturday, January 17, 2026 5:00:41 PM
>     *Subject: *Re: Data Oriented Programming, Beyond Records
>
>     Just a quick note regarding the following, given my experience in
>     this area:
>
>     On 2026-01-17 11:36, Remi Forax wrote:
>
>         A de-constructor becomes an instance method that must return a
>         carrier class/carrier interface, a type that has the
>         information to be destructured and the structure has to match
>         the one defined by the type.
>
>
> Hello Viktor,
> thanks to bring back that point,
>
>     This simply *does not work* as a deconstructor cannot be an
>     instance-method just like a constructor cannot be an instance
>     method: It strictly belongs to the type itself (not the hierarchy) and
>
>
> It can work as you said for a concrete type, but for an abstract type, 
> you need to go from the abstract definition to the concrete one,
> if you do not want to re-invent the wheel here, the deconstructor has 
> to be an abstract instance method.
>
> For example, with a non-public named implementation
>
> interface Pair<F, S>(F first, S second) {
>   public <F,S> Pair<F,S> of(F first, S second) {
>     record Impl<F, S>(F first, S second) implements Pair<F, S>{ }
>     return new Impl<>(first, second);
>   }
> }
>
> inside Pair, there is no concrete field first and second, so you need 
> a way to extract them from the implementation.
>
> This can be implemented either using accessors (first() and second()) 
> but you have a problem if you want your implementation to be mutable 
> and synchronized on a lock (because the instance can be changed in 
> between the call to first() and the call to second()) or you can have 
> one abstract method, the deconstructor.
>
>     it doesn't play well with implementing multiple interfaces (name
>     clashing), and interacts poorly with overload resolution (instead
>     of choosing most-specific, you need to select a specific point in
>     the hierarchy to call the method). 
>
>
> It depends on the compiler translation, but if you limit yourself to 
> one destructor per class (the dual of the canonical constructor), the 
> deconstructor can be desugared to one instance method that takes 
> nothing and return java.lang.Object, so no name clash and no problem 
> of overloading (because overloading is not allowed, you have to use 
> '_' at use site).
>
>     -- 
>     Cheers,
>>
>
> regards,
> Rémi
>
>     Viktor Klang
>     Software Architect, Java Platform Group
>     Oracle
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20260117/304d916d/attachment-0001.htm>


More information about the amber-spec-experts mailing list