Idea: guaranteed object-level immutability, like in JavaScript's Object.freeze()

John Rose john.r.rose at
Tue Sep 29 19:58:46 UTC 2020

On Sep 29, 2020, at 11:30 AM, Piotr Tarsa <piotr.tarsa at> wrote:
> ...Do you think freezing objects could make sense for Java?

Short answer: Maybe, eventually.  But not like JavaScript.

You mention race conditions as a potential problem.  One
way to manage that would be to tie the new object states to
the existing state transitions involving the synchronization
monitor.  That opens up a large design conversation about
how to extend Java’s (rather antiquated) locking intrinsics
to support more kinds of anti-race design patterns.

The biggest problem is building a user model that answers
questions like, “when is it useful?” and “who has privileges
to freeze an object?” and “what happens when there’s a mix
of frozen and unfrozen objects in a workload”?  And of course,
“are frozen objects the same type as their ordinary siblings,
or somehow a different type?”  There are no easy answers
here, simply because any eventual design has to work well
with millions of existing APIs and programs.  I *do* think
there are probably “hard” answers out there.

Currently, Project Panama is experimenting with confinement
models for native (C-heap) data structures.  We are learning a lot in
this exercise.  When things settle down, I think we might
transfer some of our learnings across to Java heap data
structures.  Note that confinement is a useful generalization
of freezing, because both confinement and freezing make
useful statements about who can and cannot modify an
object field.  A confined field is mutable only by one (or
a limited set) of threads.  A frozen field is mutable by
no threads at all.  When passing mutable data between
threads, it is (arguably) useful to be able “park” the data
in the confined-to-no-thread state while it is queued for
processing, having been originally confined-to-sender-thread
and eventually (after dequeueing) confined-to-receiver-thread
for further processing.  Arguably.  My point here is that,
not only does freezing all by itself raise difficult design
questions (as well as implementation questions which
are frankly easy by comparison), but freezing also raises
the question of “what is the correct set of primitives
for race control”, since freezing is not a lone primitive,
but rather one of a set of possible ones.

Another variation on the “freeze” theme is lazy fields.
The JDK uses lazy evaluation internally in many places,
but the language does not provide all the ways we might
wish to express lazily evaluated fields.  (So we’ve had to
invent off-label mechanisms like @Stable.)  The point
of a lazy field is it starts out with no value and then
acquires its value at some use point, and freezes that
value at the same time.

The generalization which covers all of these cases
(as well as today’s existing regular and final fields) is
being able to write stories about the mutability state of
a field, saying when it can be modified and by who,
and how the mutability state can be changed (if at all).
There are many possible such stories; I’ve identified
the ones which seems promising to me above.


— John

More information about the discuss mailing list