<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"><meta name=Generator content="Microsoft Word 12 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
{font-family:Wingdings;
panose-1:5 0 0 0 0 0 0 0 0 0;}
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
{font-family:Tahoma;
panose-1:2 11 6 4 3 5 4 4 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0cm;
margin-bottom:.0001pt;
font-size:12.0pt;
font-family:"Times New Roman","serif";}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:purple;
text-decoration:underline;}
span.gmailsignatureprefix
{mso-style-name:gmail_signature_prefix;}
span.E-MailFormatvorlage18
{mso-style-type:personal-reply;
font-family:"Calibri","sans-serif";
color:#1F497D;}
.MsoChpDefault
{mso-style-type:export-only;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:70.85pt 70.85pt 2.0cm 70.85pt;}
div.WordSection1
{page:WordSection1;}
/* List Definitions */
@list l0
{mso-list-id:138160098;
mso-list-template-ids:2128218190;}
@list l0:level1
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l0:level2
{mso-level-number-format:bullet;
mso-level-text:o;
mso-level-tab-stop:72.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:"Courier New";
mso-bidi-font-family:"Times New Roman";}
@list l1
{mso-list-id:632366427;
mso-list-template-ids:-1103469314;}
@list l1:level1
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l1:level2
{mso-level-number-format:bullet;
mso-level-text:o;
mso-level-tab-stop:72.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:"Courier New";
mso-bidi-font-family:"Times New Roman";}
ol
{margin-bottom:0cm;}
ul
{margin-bottom:0cm;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]--></head><body lang=DE link=blue vlink=purple><div class=WordSection1><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>It was just today that I asked Brian for frozen arrays. I would love to get this, as it could help us with performance problems in IO and NIO.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>-Markus<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><p class=MsoNormal><a name="_MailEndCompose"><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></a></p><div style='border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0cm 0cm 0cm'><p class=MsoNormal><b><span style='font-size:10.0pt;font-family:"Tahoma","sans-serif"'>Von:</span></b><span style='font-size:10.0pt;font-family:"Tahoma","sans-serif"'> amber-dev [mailto:amber-dev-retn@openjdk.org] <b>Im Auftrag von </b>Archie Cobbs<br><b>Gesendet:</b> Samstag, 16. Dezember 2023 18:33<br><b>An:</b> amber-dev<br><b>Betreff:</b> Frozen objects?<o:p></o:p></span></p></div><p class=MsoNormal><o:p> </o:p></p><div><div><p class=MsoNormal>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.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>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.<o:p></o:p></p></div><div><div><div><div><p class=MsoNormal><o:p> </o:p></p></div></div><div><p class=MsoNormal>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).<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div></div><div><p class=MsoNormal>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.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>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.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>Summary of differences between C 'const' and Java 'final':<o:p></o:p></p></div><div><ul type=disc><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l1 level1 lfo1'>Granularity:<o:p></o:p></li></ul><ul type=disc><ul type=circle><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l1 level2 lfo1'>C: Any contiguous memory region that has a language name/identification<o:p></o:p></li><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l1 level2 lfo1'>Java: At most 64 bits at a time (*) and arrays are not included<o:p></o:p></li><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l1 level2 lfo1'>Advantage: C<o:p></o:p></li></ul></ul><ul type=disc><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l1 level1 lfo1'>Enforcement:<o:p></o:p></li></ul><ul type=disc><ul type=circle><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l1 level2 lfo1'>C: Enforced only by the compiler (mostly)<o:p></o:p></li><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l1 level2 lfo1'>Java: Enforced by the compiler and at runtime<o:p></o:p></li><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l1 level2 lfo1'>Advantage: Java<o:p></o:p></li></ul></ul><ul type=disc><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l1 level1 lfo1'>Dynamic Application:<o:p></o:p></li></ul><ul type=disc><ul type=circle><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l1 level2 lfo1'>C: Yes<o:p></o:p></li><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l1 level2 lfo1'>Java: No<o:p></o:p></li><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l1 level2 lfo1'>Advantage: C<o:p></o:p></li></ul></ul></div><p class=MsoNormal>(*) 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.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>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?<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>In other words, add the ability to "freeze" an object or array. If 'x' is frozen, whatever 'x' directly references becomes no longer mutable.<o:p></o:p></p></div><p class=MsoNormal><o:p> </o:p></p><div><p class=MsoNormal>A rough sketch...<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>Add new <span style='font-family:"Courier New"'>Freezable</span> interface:<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><div><p class=MsoNormal><span style='font-family:"Courier New"'> public interface Freezable {</span><o:p></o:p></p></div><div><p class=MsoNormal><span style='font-family:"Courier New"'> boolean isFrozen();</span><o:p></o:p></p></div><div><p class=MsoNormal><span style='font-family:"Courier New"'> static boolean freeze(Freezable obj); // returns false if already frozen</span><o:p></o:p></p></div><div><p class=MsoNormal><span style='font-family:"Courier New"'> }</span><o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>Arrays automatically implement <span style='font-family:"Courier New"'>Freezable</span> (just like they do <span style='font-family:"Courier New"'>Cloneable</span>)<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>What about the memory model? Ideally it would work as if written like this:<o:p></o:p></p></div></div><div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal><span style='font-family:"Courier New"'> public class Foo implements Freezable {</span><o:p></o:p></p></div><div><p class=MsoNormal><span style='font-family:"Courier New"'> private volatile frozen; // set to true by Freezable.freeze()</span><o:p></o:p></p></div><div><p class=MsoNormal><span style='font-family:"Courier New"'> void mutateFooContent(Runnable mutation) {</span><o:p></o:p></p></div><div><p class=MsoNormal><span style='font-family:"Courier New"'> if (this.frozen)</span><o:p></o:p></p></div><div><p class=MsoNormal><span style='font-family:"Courier New"'> throw new FrozenObjectException();</span><o:p></o:p></p></div><div><div><p class=MsoNormal><span style='font-family:"Courier New"'> else</span><o:p></o:p></p></div></div><div><p class=MsoNormal><span style='font-family:"Courier New"'> mutation.run();</span><o:p></o:p></p></div><div><p class=MsoNormal><span style='font-family:"Courier New"'> }</span><o:p></o:p></p></div><div><p class=MsoNormal><span style='font-family:"Courier New"'> }</span><o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>But there could be a better trade-off of performance vs. semantics.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div></div><div><p class=MsoNormal>Other trade-offs...<o:p></o:p></p></div><div><ul type=disc><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l0 level1 lfo2'>(-) All mutations to a <span style='font-family:"Courier New"'>Freezable</span> would require a new 'frozen' check (* see below)<o:p></o:p></li><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l0 level1 lfo2'>(-) There would have to be a new bit allocated in the object header<o:p></o:p></li><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l0 level1 lfo2'>(+) Eliminate zillions of JDK defensive array copies (things like <span style='font-family:"Courier New"'>String.toCharArray()</span>)<o:p></o:p></li><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l0 level1 lfo2'>(+) JIT optimizations for constant-folding, etc.<o:p></o:p></li><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l0 level1 lfo2'>(+) GC optimizations<o:p></o:p></li></ul><ul type=disc><ul type=circle><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l0 level2 lfo2'>(*) Put frozen objects into a read-only region of memory to eliminate mutation checks<o:p></o:p></li><li class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l0 level2 lfo2'>Optimize scanning of frozen references (since they never change)<o:p></o:p></li></ul></ul></div><div><p class=MsoNormal>I'm curious how other people think this idea would or wouldn't make sense for Java & what's been decided in the past.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>Thanks,<o:p></o:p></p></div><div><p class=MsoNormal>-Archie<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><div><p class=MsoNormal><span class=gmailsignatureprefix>-- </span><o:p></o:p></p><div><p class=MsoNormal>Archie L. Cobbs<o:p></o:p></p></div></div></div></div></div></body></html>