<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<font size="4" face="monospace">These are subtle issues. Here are
some considerations to think about. <br>
<br>
Even final fields are mutable at certain points in their
lifecycle, such as during construction. There are verifier rules
that will let a final field be mutated by the constructor
declaring the field (even multiple times in the same constructor
invocation, which the language prohibits but the VM allows.)
There are also some off-label channels for mutating final fields,
such as during deserialization, and reflection also offers the
ability to bust finality and access control on some fields through
setAccessible, but the set of limitations on that is growing
(good). <br>
<br>
Ignoring whether "final means final" (grr), classes already offer
some ability to provide freezing through the use of final fields.
And value objects will take this further, giving the VM permission
to freely scalarize and reassemble value objects as needed. This
provides much of the benefit you hope to get from freezing, in
that it tells the VM at the aggregate level that the object need
not be copied (and also, can be copied freely.)<br>
<br>
Where we have a real gap is with arrays; we cannot at present make
arrays unmodifiable. This is not an irremediable, in the sense
that we already have error paths on `aastore` (dynamic type checks
and ArrayStoreException.) But what is missing is the programming
model, because arrays lack constructors -- there's no body of code
in which we can draw the circle of mutability for arrays as we can
with objects. We've discussed two ways to do this:<br>
<br>
- a primitive for allocating an array and running a function to
initialize every element, which is guaranteed to run successfully
for each element before the reference is dispensed;<br>
<br>
- a "freeze" operation on arrays, which acts like a copy, but if
the array is already frozen just returns its own reference. <br>
<br>
Both of these have their uses. <br>
<br>
<br>
</font><br>
<div class="moz-cite-prefix">On 12/16/2023 12:32 PM, Archie Cobbs
wrote:<br>
</div>
<blockquote type="cite" cite="mid:CANSoFxteVNhWiK9EfAzcwxs_LKpbCZ-6i=PAOV2EPbfdcQaHKw@mail.gmail.com">
<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>
<div><br>
</div>
<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>
<div><br>
</div>
</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>
<div><br>
</div>
</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>
<div><br>
</div>
<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>
<div><br>
</div>
<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>
<div><br>
</div>
<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>
<div><br>
</div>
<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>
<div><br>
</div>
<div>Add new <span style="font-family:monospace">Freezable</span>
interface:</div>
<div><br>
</div>
<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>
<div><br>
</div>
<div>What about the memory model? Ideally it would work as if
written like this:</div>
</div>
<div>
<div><br>
</div>
<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>
<div><br>
</div>
<div>But there could be a better trade-off of performance vs.
semantics.<br>
</div>
<div><br>
</div>
</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>
<div><br>
</div>
<div>Thanks,<br>
</div>
<div>-Archie</div>
<div><br>
</div>
<div>
<div><span class="gmail_signature_prefix">-- </span><br>
<div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">Archie L. Cobbs<br>
</div>
</div>
</div>
</div>
</blockquote>
<br>
</body>
</html>