<html><body><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div><br></div><div><br></div><hr id="zwchr" data-marker="__DIVIDER__"><div data-marker="__HEADERS__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From: </b>"Viktor Klang" <viktor.klang@oracle.com><br><b>To: </b>"Brian Goetz" <brian.goetz@oracle.com>, "Remi Forax" <forax@univ-mlv.fr><br><b>Cc: </b>"amber-spec-experts" <amber-spec-experts@openjdk.java.net><br><b>Sent: </b>Monday, January 19, 2026 1:08:05 AM<br><b>Subject: </b>Re: Data Oriented Programming, Beyond Records<br></blockquote></div><div data-marker="__QUOTED_TEXT__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><p>Since someone said <b>synchronized</b>, I was summoned.</p></blockquote><div><br></div><div>:)</div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><p><br>
<br>
If a definition of deconstruction is isomorphic to an instance-of
check plus invoking N accessors, it is clear that it would have
the same atomicity as invoking the accessors directly (i.e. none).</p>
<p>I would say that it is much more consistent, than to try to
create special-cases with different atomicity guarantees. Also,
there is nothing which prevents exposing a "shapshot"-method which
returns a record (or other carrier class) if one wants atomicity
in matching:<br>
<br>
switch (foo) {<br>
case Foo foo when foo.snapshot() instanceof FooSnapshot(var x,
var y) -><br>
}<br>
<br>
PS. it's worth noting that this only applies to types which can
enforce stable snapshotting, either via <b>synchronized</b> or
via optimistic concurrency control schemes such as STM.</p></blockquote><div><br></div><div>yes,</div><div>snapshoting is a good term to describe the semantics.</div><div><br data-mce-bogus="1"></div><div>Conceptually, you do not want your object to change state in the middle of the pattern matching, so you snapshot it.</div><div><br data-mce-bogus="1"></div><div>For me, this is no different from having a value class to guarantee atomicity by default, by default pattern matching should guarantee that you can not see an object in a state that does not exist. </div><div><br data-mce-bogus="1"></div><div>I do not like the fact that a user has to call .snapshot() explicitly because it goes against the idea that in Java, a thread safe class is like any other class from the user POV, the maintainer of the class has to do more work, but from the user POV a thread safe class works like any other classes.</div><div>Here you are asking the thread safe classes to have an extra step at use site when using pattern matching.</div><div><br data-mce-bogus="1"></div><div>That why i said that by not providing snapshoting by default, it makes thread safe classes are not first class objects anymore</div><div> see https://en.wikipedia.org/wiki/First-class_citizen</div><div><br data-mce-bogus="1"></div><div>regards,</div><div>Rémi</div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;">
<div class="moz-cite-prefix">On 2026-01-18 17:57, Brian Goetz wrote:<br>
</div>
<blockquote cite="mid:071138f8-ba07-465a-94be-3e51c2d91ffb@oracle.com">
You're trying to make a point, but you're walking all around it
and not making it directly, so I can only guess at what you
mean. I think your point is: "if you're going to embrace
mutability, you should also embrace thread-safety" (but actually,
I think you are really trying to argue against mutability, but you
didn't use any of those words, so again, we're only guessing at
what you really mean.)<br>
<br>
A mutable carrier can be made thread-safe by protecting the state
with locks or volatile fields or delegation to thread-safe
containers, as your example shows. And since pattern matching
proceeds through accessors, it will get the benefit of those
mechanisms to get race-freedom for free. But you want (I think )
more: that the dtor not only retrieves the latest value of all the
components, but that it must be able to do so _atomically_. <br>
<br>
I think the case you are really appealing to is one where there an
invariant that constrains the state, such as a mutable Range,
because then if one observed a range mid-update and unpacked the
bounds, they could be seen to be inconsistent. So let's take
that: <br>
<br>
class Range(int lo, int hi) { <br>
private int lo, hi;<br>
<br>
Range { <br>
if (lo > hi) throw new IAE();<br>
}<br>
<br>
// accessors synchronized on known monitor, such as
`this`<br>
}<br>
<br>
Now, while a client will always see up-to-date values for the
range components (Range is race-free), the worry is that they
might see something _too_ up-to-date, which is to say, seeing a
range mid-update:<br>
<br>
case Range(var lo, var hi): <br>
<br>
while another thread does<br>
<br>
sync (monitor of range) { range.lo += 5; range.hi += 5; }<br>
<br>
If the range is initially (0,1), with some bad timing, the client
could see lo=6, hi=1 get unpacked, and scratch their heads about
what happened. <br>
<br>
This is analogous to the case where we have an ArrayList wrapped
with a synchronizedList; while access to the list's state is
race-free, if you want a consistent snapshot (such as iterating
it), you have to hold the lock for the duration of the composite
operation. Similarly, if you have a mutable carrier that might be
concurrently modified, and you care about seeing updates
atomically, you would have to hold the lock during the pattern
match:<br>
<br>
sync (monitor of range) { Range(var lo, var hi) = range; ...
use lo/hi ... }<br>
<br>
I think the argument you are (not) making goes like this:<br>
<br>
- We will have no chance to get users to understand that
deconstruction is not atomic, because it just _looks_ so atomic!<br>
- Therefore, we either have to find a way so it can be made
atomic, OR (I think your preference), outlaw mutable carriers in
the first place. <br>
<br>
(I really wish you would just say what you mean, rather than
making us guess and make your arguments for you...)<br>
<br>
While there's a valid argument there to make here (if you actually
made it), I'll just note that the leap from "something bad and
surprising can happen" to "so, this design needs to be radically
overhauled" is ... quite a leap. <br>
<br>
(This is kind of the same leap you made about hash-based
collections: "there is a risk, therefore we must neuter the
feature so there are no risks." Rather than leaping to "so let's
change the design center", I would rather have a conversation
about what risks there _are_, and whether they are acceptable, or
whether the cure is worse than the disease.)<br>
<br>
<br>
<br>
<br>
<br>
<div class="moz-cite-prefix">On 1/18/2026 7:49 AM, <a class="moz-txt-link-abbreviated moz-txt-link-freetext" href="mailto:forax@univ-mlv.fr" target="_blank">forax@univ-mlv.fr</a>
wrote:<br>
</div>
<blockquote cite="mid:1710737945.19433405.1768740540151.JavaMail.zimbra@univ-eiffel.fr">
<div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000">
<div><br>
</div>
<div><br>
</div>
<hr id="zwchr">
<div>
<blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From:
</b>"Brian Goetz" <a class="moz-txt-link-rfc2396E" href="mailto:brian.goetz@oracle.com" target="_blank"><brian.goetz@oracle.com></a><br>
<b>To: </b>"Remi Forax" <a class="moz-txt-link-rfc2396E" href="mailto:forax@univ-mlv.fr" target="_blank"><forax@univ-mlv.fr></a>,
"Viktor Klang" <a class="moz-txt-link-rfc2396E" href="mailto:viktor.klang@oracle.com" target="_blank"><viktor.klang@oracle.com></a><br>
<b>Cc: </b>"amber-spec-experts" <a class="moz-txt-link-rfc2396E" href="mailto:amber-spec-experts@openjdk.java.net" target="_blank"><amber-spec-experts@openjdk.java.net></a><br>
<b>Sent: </b>Sunday, January 18, 2026 2:00:19 AM<br>
<b>Subject: </b>Re: Data Oriented Programming, Beyond
Records<br>
</blockquote>
</div>
<div>
<blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><font size="4" face="monospace">In reality, the deconstructor
is not a method at all. <br><br>
When we match:<br><br>
x instanceof R(P, Q)<br><br>
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.</font></blockquote>
<div><br>
</div>
<div>Pattern matching and late binding are dual only for
public types,</div>
<div>if an implementation class (the one containing the
fields) is not visible from outside, the way to get to
fields is by using late binding.</div>
<div><br>
</div>
<div>If the only way to do the late binding is by using
accessors, then you can not guarantee the atomicity of the
deconstruction,</div>
<div>or said differently the pattern matching will be able
to see states that does not exist.</div>
<div><br>
</div>
<div>Let say I have a public thread safe class containing
two fields, and I want see that class has a carrier class,</div>
<div>with the idea that a carrier class either provide a
deconstructor method or accessors.</div>
<div>I can write the following code :</div>
<div><br>
</div>
<div> public final class ThreadSafeData(String name, int
age) {</div>
<div> private String name;</div>
<div> private int age;</div>
<div> private final Object lock = new Object();</div>
<div><br>
</div>
<div> public ThreadSafeData(String name, int age) {</div>
<div> synchronized(lock) {
<div> this.name = name;</div>
<div> this.age = age;</div>
<div> } </div>
</div>
<div> }</div>
<div><br>
</div>
<div> public void set(String name, int age) {</div>
<div> synchronized(lock) {</div>
<div> this.name = name;</div>
<div> this.age = age;</div>
<div> }</div>
<div> }<br>
<br>
</div>
<div>
<div> public String toString() {</div>
<div> synchronized(lock) {</div>
<div> return name + " " + age;</div>
<div> }</div>
<div> }</div>
</div>
<div><br>
</div>
<div> public deconstructor() {. // no return type, the
compiler checks that the return values have the same
carrier definition</div>
<div> record Tuple(String name, int age) { }</div>
<div> synchronized(lock) {</div>
<div> return new Tuple(name, age);</div>
<div> }</div>
<div> }</div>
<div><br>
</div>
<div> // no accessors here, if you want to have access
the state, use pattern matching like this</div>
<div> // ThreadSafeHolder holder = ...</div>
<div> // ThreadSafeHolder(String name, int age) =
holder;</div>
<div> }</div>
<div> </div>
<div>I understand that you are trying to drastically
simplify the pattern matching model (yai !) by removing
the deconstructor method but by doing that you are making
thread safe classes second class citizens. </div>
<div> </div>
<div>regards,</div>
<div>Rémi</div>
<div><br>
</div>
<blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><font size="4" face="monospace"><br></font><br>
<div class="moz-cite-prefix">On 1/17/2026 5:09 PM, <a class="moz-txt-link-abbreviated moz-txt-link-freetext" href="mailto:forax@univ-mlv.fr" target="_blank">forax@univ-mlv.fr</a> wrote:<br>
</div>
<blockquote cite="mid:1864311863.19305629.1768687793277.JavaMail.zimbra@univ-eiffel.fr">
<div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000">
<div><br>
</div>
<div><br>
</div>
<hr id="zwchr">
<div>
<blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From:
</b>"Viktor Klang" <a class="moz-txt-link-rfc2396E" href="mailto:viktor.klang@oracle.com" target="_blank"><viktor.klang@oracle.com></a><br>
<b>To: </b>"Remi Forax" <a class="moz-txt-link-rfc2396E" href="mailto:forax@univ-mlv.fr" target="_blank"><forax@univ-mlv.fr></a>,
"Brian Goetz" <a class="moz-txt-link-rfc2396E" href="mailto:brian.goetz@oracle.com" target="_blank"><brian.goetz@oracle.com></a><br>
<b>Cc: </b>"amber-spec-experts" <a class="moz-txt-link-rfc2396E" href="mailto:amber-spec-experts@openjdk.java.net" target="_blank"><amber-spec-experts@openjdk.java.net></a><br>
<b>Sent: </b>Saturday, January 17, 2026 5:00:41
PM<br>
<b>Subject: </b>Re: Data Oriented Programming,
Beyond Records<br>
</blockquote>
</div>
<div>
<blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;">
<p>Just a quick note regarding the following,
given my experience in this area:</p>
<div class="moz-cite-prefix">On 2026-01-17 11:36,
Remi Forax wrote:<br>
</div>
<blockquote cite="mid:1085557496.17567763.1768646213005.JavaMail.zimbra@univ-eiffel.fr">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.</blockquote>
</blockquote>
<div><br>
</div>
<div>Hello Viktor,</div>
<div>thanks to bring back that point,</div>
<div><br>
</div>
<blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;">
This simply <b>does not work</b> 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</blockquote>
<div><br>
</div>
<div>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,</div>
<div>if you do not want to re-invent the wheel here,
the deconstructor has to be an abstract instance
method.</div>
<div><br>
</div>
<div>For example, with a non-public named
implementation</div>
<div><br>
</div>
<div>interface Pair<F, S>(F first, S second) {</div>
<div> public <F,S> Pair<F,S> of(F
first, S second) {</div>
<div> record Impl<F, S>(F first, S second)
implements Pair<F, S>{ }</div>
<div> return new Impl<>(first, second);</div>
<div> }</div>
<div>}</div>
<div><br>
</div>
<div>inside Pair, there is no concrete field first
and second, so you need a way to extract them from
the implementation.</div>
<div><br>
</div>
<div>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.</div>
<div><br>
</div>
<blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;">
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). </blockquote>
<div><br>
</div>
<div>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).</div>
<div><br>
</div>
<blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;">
<pre class="moz-signature">--
Cheers,
√</pre>
</blockquote>
<div><br>
</div>
<div>regards,</div>
<div>Rémi</div>
<div><br>
</div>
<blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;">
<pre class="moz-signature">Viktor Klang
Software Architect, Java Platform Group
Oracle</pre>
<br>
</blockquote>
</div>
</div>
</blockquote>
<br>
<br>
</blockquote>
</div>
</div>
</blockquote>
<br>
</blockquote>
<pre class="moz-signature">--
Cheers,
√
Viktor Klang
Software Architect, Java Platform Group
Oracle</pre><br></blockquote></div></div></body></html>