<div dir="auto"><div>I think that indeed the main concern for the run time is races, but even ignoring races, there is (almost*) no real to make the compiler know when there is no illegal access to the values.</div><div dir="auto"><br></div><div dir="auto">I do not think that introducing a language level/runtime mechanism that has a consequences on what is a valid code without a real way enforce it is good.</div><div dir="auto"><br></div><div dir="auto">*Like Brian G. Said, final fields has a specific time in their lifecycle where they can be modified which does allow the compiler to do it's job, the only way (I can think of) to have a user code at an enforced lifecycle currently is through passing scopes (/continuations/lambdas/however you want to call them) to the said object, and have the object implement a mechanism to run these scopes.</div><div dir="auto"><br></div><div dir="auto">I'll advocate for this every time I can, I believe that we should start a conversation about designing a way to have a better control at the lifecycle of an object. (E.g. enhanced try-with-resources of sort)</div><div dir="auto"><br><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Tue, 19 Dec 2023, 01:56 Dan Heidinga, <<a href="mailto:dan.heidinga@oracle.com" target="_blank" rel="noreferrer">dan.heidinga@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div lang="EN-CA" link="#0563C1" vlink="#954F72" style="word-wrap:break-word">
<div>
<p class="MsoNormal"><span style="font-size:11.0pt">Let me throw out one other concern: races. The invariant frozen objects want is that the application and runtime can trust they will never be mutated again. Unfortunately, if the object is published across
threads before it is frozen, then that invariant is very difficult and expensive to maintain.<u></u><u></u></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt">If two threads, A & B, both have references to the object and thread A freezes it, B may still be publishing writes to it that A only observes later. To ensure the right JMM happens-before relationship for
fields of Freezable objects, both reads and writes would need to be more expensive (volatile semantics?) until a thread could validate the object it was operating on was frozen.<u></u><u></u></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt">Freezing is not just a free set of unexplored optimizations. There’re also new costs associated with it across the runtime (field read/write, profiling, etc).
<u></u><u></u></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt">--Dan<u></u><u></u></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
<div id="m_-5650743233653280517m_-5355378415525858311mail-editor-reference-message-container">
<div>
<div style="border:none;border-top:solid #b5c4df 1.0pt;padding:3.0pt 0cm 0cm 0cm">
<p class="MsoNormal" style="margin-right:0cm;margin-bottom:12.0pt;margin-left:36.0pt">
<b><span style="font-size:12.0pt;color:black">From: </span></b><span style="font-size:12.0pt;color:black">amber-dev <<a href="mailto:amber-dev-retn@openjdk.org" rel="noreferrer noreferrer" target="_blank">amber-dev-retn@openjdk.org</a>> on behalf of Archie Cobbs <<a href="mailto:archie.cobbs@gmail.com" rel="noreferrer noreferrer" target="_blank">archie.cobbs@gmail.com</a>><br>
<b>Date: </b>Saturday, December 16, 2023 at 12:33 PM<br>
<b>To: </b>amber-dev <<a href="mailto:amber-dev@openjdk.org" rel="noreferrer noreferrer" target="_blank">amber-dev@openjdk.org</a>><br>
<b>Subject: </b>Frozen objects?<u></u><u></u></span></p>
</div>
<div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">Caveat: I'm just trying to educate myself on what's been discussed in the past, not actually suggest a new language feature. I'm sure this kind of idea has been discussed before
so feel free to point me at some previous thread, etc.<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">In C we have 'const' which essentially means "the memory allocated to this thing is immutable". The nice thing about 'const' is that it can apply to an individual variable or field
in a structure, or it can apply to an entire C structure or C array. In effect it applies to any contiguous memory region that can be named/identified at the language level.<u></u><u></u></span></p>
</div>
<div>
<div>
<div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">On the other hand, it's just a language fiction, i.e., it can always be defeated at runtime by casting (except for static constants).<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">In Java we have 'final' which (in part) is like 'const' for fields and variables, but unlike C 'final' can't be applied to larger memory regions like entire objects or entire arrays.<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">In C, 'const' can be applied "dynamically" in the sense I can cast foo to const foo. Of course, this is only enforced at the language level.<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">Summary of differences between C 'const' and Java 'final':<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:72.0pt">
<u></u><span style="font-family:Symbol"><span>·<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">Granularity:<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:108.0pt">
<u></u><span style="font-family:"Courier New",serif"><span>o<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">C: Any contiguous memory region that has a language name/identification<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:108.0pt">
<u></u><span style="font-family:"Courier New",serif"><span>o<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">Java: At most 64 bits at a time (*) and arrays are not included<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:108.0pt">
<u></u><span style="font-family:"Courier New",serif"><span>o<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">Advantage: C<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:72.0pt">
<u></u><span style="font-family:Symbol"><span>·<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">Enforcement:<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:108.0pt">
<u></u><span style="font-family:"Courier New",serif"><span>o<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">C: Enforced only by the compiler (mostly)<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:108.0pt">
<u></u><span style="font-family:"Courier New",serif"><span>o<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">Java: Enforced by the compiler and at runtime<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:108.0pt">
<u></u><span style="font-family:"Courier New",serif"><span>o<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">Advantage: Java<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:72.0pt">
<u></u><span style="font-family:Symbol"><span>·<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">Dynamic Application:<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:108.0pt">
<u></u><span style="font-family:"Courier New",serif"><span>o<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">C: Yes<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:108.0pt">
<u></u><span style="font-family:"Courier New",serif"><span>o<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">Java: No<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:108.0pt">
<u></u><span style="font-family:"Courier New",serif"><span>o<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">Advantage: C<u></u><u></u></span></p>
</div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">(*) With records and value objects we are gradually moving towards the ability for larger things than an individual field to be 'const'. More generally, Java has slowly been glomming
on some of the goodness from functional programming, including making it easier to declare and work with immutable data.<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">This all begs the question: why not take this idea to its logical conclusion? And while we're at it, make the capability fully dynamic, instead of limiting when you can 'freeze'
something construction time?<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">In other words, add the ability to "freeze" an object or array. If 'x' is frozen, whatever 'x' directly references becomes no longer mutable.<u></u><u></u></span></p>
</div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">A rough sketch...<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">Add new
</span><span style="font-size:11.0pt;font-family:"Courier New",serif">Freezable</span><span style="font-size:11.0pt"> interface:<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> public interface Freezable {</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> boolean isFrozen();</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> static boolean freeze(Freezable obj); // returns false if already frozen</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> }</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">Arrays automatically implement
</span><span style="font-size:11.0pt;font-family:"Courier New",serif">Freezable</span><span style="font-size:11.0pt"> (just like they do
</span><span style="font-size:11.0pt;font-family:"Courier New",serif">Cloneable</span><span style="font-size:11.0pt">)<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">What about the memory model? Ideally it would work as if written like this:<u></u><u></u></span></p>
</div>
</div>
<div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> public class Foo implements Freezable {</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> private volatile frozen; // set to true by Freezable.freeze()</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> void mutateFooContent(Runnable mutation) {</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> if (this.frozen)</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> throw new FrozenObjectException();</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
<div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> else</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> mutation.run();</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> }</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt;font-family:"Courier New",serif"> }</span><span style="font-size:11.0pt"><u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">But there could be a better trade-off of performance vs. semantics.<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">Other trade-offs...<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:72.0pt">
<u></u><span style="font-family:Symbol"><span>·<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">(-) All mutations to a
</span><span style="font-size:11.0pt;font-family:"Courier New",serif">Freezable</span><span style="font-size:11.0pt"> would require a new 'frozen' check (* see below)<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:72.0pt">
<u></u><span style="font-family:Symbol"><span>·<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">(-) There would have to be a new bit allocated in the object header<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:72.0pt">
<u></u><span style="font-family:Symbol"><span>·<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">(+) Eliminate zillions of JDK defensive array copies (things like
</span><span style="font-size:11.0pt;font-family:"Courier New",serif">String.toCharArray()</span><span style="font-size:11.0pt">)<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:72.0pt">
<u></u><span style="font-family:Symbol"><span>·<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">(+) JIT optimizations for constant-folding, etc.<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:72.0pt">
<u></u><span style="font-family:Symbol"><span>·<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">(+) GC optimizations<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:108.0pt">
<u></u><span style="font-family:"Courier New",serif"><span>o<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">(*) Put frozen objects into a read-only region of memory to eliminate mutation checks<u></u><u></u></span></p>
<p class="MsoNormal" style="margin-left:108.0pt">
<u></u><span style="font-family:"Courier New",serif"><span>o<span style="font:7.0pt "Times New Roman"">
</span></span></span><u></u><span style="font-size:11.0pt">Optimize scanning of frozen references (since they never change)<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">I'm curious how other people think this idea would or wouldn't make sense for Java & what's been decided in the past.<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">Thanks,<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">-Archie<u></u><u></u></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt"><u></u> <u></u></span></p>
</div>
<div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span><span style="font-size:11.0pt">--
</span></span><span style="font-size:11.0pt"><u></u><u></u></span></p>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-size:11.0pt">Archie L. Cobbs<u></u><u></u></span></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</blockquote></div></div></div>