<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>