<html><body><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div>Hello,<br data-mce-bogus="1"></div><div>As part of Valhalla, the VM support for what you want to do already exists because we need something similar to be able to deserialize a value class.</div><div>jdk.internal.misc.Unsafe provides several methods: makePrivateBuffer(), put*() and finishPrivateBuffer() [1].<br></div><div><br data-mce-bogus="1"></div><div>Compared to your interface Freezable, the method equivalent of the method freeze(), finishPrivateBuffer() needs to returns a value so the VM/JIT can separate the reference to a piece of memory which is mutable from the reference to the same piece of memory which is frozen.<br data-mce-bogus="1"></div><div></div><div><br data-mce-bogus="1"></div><div>regards,<br data-mce-bogus="1"></div><div>RĂ©mi<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>[1] <a href="https://github.com/openjdk/valhalla/blob/lworld/src/java.base/share/classes/jdk/internal/misc/Unsafe.java#L299" data-mce-href="https://github.com/openjdk/valhalla/blob/lworld/src/java.base/share/classes/jdk/internal/misc/Unsafe.java#L299">https://github.com/openjdk/valhalla/blob/lworld/src/java.base/share/classes/jdk/internal/misc/Unsafe.java#L299</a><br></div><div><br data-mce-bogus="1"></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>"Archie Cobbs" <archie.cobbs@gmail.com><br><b>To: </b>"amber-dev" <amber-dev@openjdk.org><br><b>Sent: </b>Saturday, December 16, 2023 6:32:59 PM<br><b>Subject: </b>Frozen objects?<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;"><div dir="ltr"><div>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.<br></div><br><div>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.<br></div><div><div><div><br></div><div>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).</div><br></div><div>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.</div><br><div>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.<br></div><br><div>Summary of differences between C 'const' and Java 'final':</div><div><ul><li>Granularity:</li><ul><li>C: Any contiguous memory region that has a language name/identification</li><li>Java: At most 64 bits at a time (*) and arrays are not included<br></li><li>Advantage: C<br></li></ul><li>Enforcement:</li><ul><li>C: Enforced only by the compiler (mostly)</li><li>Java: Enforced by the compiler and at runtime<br></li><li>Advantage: Java</li></ul><li>Dynamic Application:<br></li><ul><li>C: Yes<br></li><li>Java: No</li><li>Advantage: C<br></li></ul></ul></div>(*) 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.<br></div><br><div>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?</div><br><div>In other words, add the ability to "freeze" an object or array. If 'x' is frozen, whatever 'x' directly references becomes no longer mutable.<br></div><br><div>A rough sketch...</div><br><div>Add new <span style="font-family:monospace">Freezable</span> interface:</div><br><div><div><span style="font-family:monospace"> public interface Freezable {</span></div><div><span style="font-family:monospace"> boolean isFrozen();</span></div><div><span style="font-family:monospace"> static boolean freeze(Freezable obj); // returns false if already frozen</span></div><div><span style="font-family:monospace"> }<br></span></div><div><span style="font-family:monospace"><br></span></div><div>Arrays automatically implement <span style="font-family:monospace">Freezable</span> (just like they do <span style="font-family:monospace">Cloneable</span>)</div><br><div>What about the memory model? Ideally it would work as if written like this:</div></div><div><br><div><span style="font-family:monospace"> public class Foo implements Freezable {</span></div><div><span style="font-family:monospace"> private volatile frozen; // set to true by Freezable.freeze()<br></span></div><div><span style="font-family:monospace"> void mutateFooContent(Runnable mutation) {</span></div><div><span style="font-family:monospace"> if (this.frozen)</span></div><div><span style="font-family:monospace"> throw new FrozenObjectException();</span></div><div><div><span style="font-family:monospace"> else</span></div></div><div><span style="font-family:monospace"> mutation.run();</span></div><div><span style="font-family:monospace"> }</span></div><div><span style="font-family:monospace"> }<br></span></div><br><div>But there could be a better trade-off of performance vs. semantics.<br></div><br></div><div>Other trade-offs...</div><div><ul><li>(-) All mutations to a <span style="font-family:monospace">Freezable</span> would require a new 'frozen' check (* see below)<br></li><li>(-) There would have to be a new bit allocated in the object header</li><li>(+) Eliminate zillions of JDK defensive array copies (things like <span style="font-family:monospace">String.toCharArray()</span>)<br></li><li>(+) JIT optimizations for constant-folding, etc.<br></li><li>(+) GC optimizations</li><ul><li>(*) Put frozen objects into a read-only region of memory to eliminate mutation checks</li><li>Optimize scanning of frozen references (since they never change)<br></li></ul></ul></div><div>I'm curious how other people think this idea would or wouldn't make sense for Java & what's been decided in the past.<br></div><br><div>Thanks,<br></div><div>-Archie</div><br><div><div><span class="gmail_signature_prefix">-- </span><br><div dir="ltr" class="gmail_signature">Archie L. Cobbs</div></div></div></div><br></blockquote></div></div></body></html>