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