Frozen objects?
Archie Cobbs
archie.cobbs at gmail.com
Sat Dec 16 17:32:59 UTC 2023
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.
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.
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).
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.
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.
Summary of differences between C 'const' and Java 'final':
- Granularity:
- C: Any contiguous memory region that has a language
name/identification
- Java: At most 64 bits at a time (*) and arrays are not included
- Advantage: C
- Enforcement:
- C: Enforced only by the compiler (mostly)
- Java: Enforced by the compiler and at runtime
- Advantage: Java
- Dynamic Application:
- C: Yes
- Java: No
- Advantage: C
(*) 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.
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?
In other words, add the ability to "freeze" an object or array. If 'x' is
frozen, whatever 'x' directly references becomes no longer mutable.
A rough sketch...
Add new Freezable interface:
public interface Freezable {
boolean isFrozen();
static boolean freeze(Freezable obj); // returns false if already
frozen
}
Arrays automatically implement Freezable (just like they do Cloneable)
What about the memory model? Ideally it would work as if written like this:
public class Foo implements Freezable {
private volatile frozen; // set to true by Freezable.freeze()
void mutateFooContent(Runnable mutation) {
if (this.frozen)
throw new FrozenObjectException();
else
mutation.run();
}
}
But there could be a better trade-off of performance vs. semantics.
Other trade-offs...
- (-) All mutations to a Freezable would require a new 'frozen' check (*
see below)
- (-) There would have to be a new bit allocated in the object header
- (+) Eliminate zillions of JDK defensive array copies (things like
String.toCharArray())
- (+) JIT optimizations for constant-folding, etc.
- (+) GC optimizations
- (*) Put frozen objects into a read-only region of memory to
eliminate mutation checks
- Optimize scanning of frozen references (since they never change)
I'm curious how other people think this idea would or wouldn't make sense
for Java & what's been decided in the past.
Thanks,
-Archie
--
Archie L. Cobbs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20231216/f5a1186d/attachment.htm>
More information about the amber-dev
mailing list