AW: [External] : AW: Frozen objects?

Markus Karg markus at headcrashing.eu
Thu Dec 21 16:23:01 UTC 2023


So you think frozen objects will be any simpler?

-Markus

 

 

Von: Dan Heidinga [mailto:dan.heidinga at oracle.com] 
Gesendet: Donnerstag, 21. Dezember 2023 17:09
An: Markus Karg; 'Red IO'
Cc: 'Holo The Sage Wolf'; 'Archie Cobbs'; 'amber-dev'
Betreff: Re: [External] : AW: Frozen objects?

 

Not unsolvable but the payoff isn't there.

 

None of this is the hard work of figuring out what "const" would mean in the
language, how it would fit with return types, method parameters, receivers,
conversions, annotations, reflection, methodhandles, debuggers and any other
number of existing features in Java.

 

If "const" is something you really want to see added to Java, then spend the
time to work through the semantics and bring a proposal with enough details
worked out that it can be discussed and debated on its merit.

 

From: Markus Karg <markus at headcrashing.eu>
Date: Thursday, December 21, 2023 at 10:52 AM
To: 'Red IO' <redio.development at gmail.com>, Dan Heidinga
<dan.heidinga at oracle.com>
Cc: 'Holo The Sage Wolf' <holo3146 at gmail.com>, 'Archie Cobbs'
<archie.cobbs at gmail.com>, 'amber-dev' <amber-dev at openjdk.org>
Subject: AW: [External] : AW: Frozen objects?

You are right, backwards compatibility without introducing const_cast as in
C++ is a problem. But that does not neither man that we MUST introduce
const_cast nor that the problem is not solvable.

-Markus

 

 

Von: Red IO [mailto:redio.development at gmail.com] 
Gesendet: Donnerstag, 21. Dezember 2023 16:06
An: Dan Heidinga
Cc: Markus Karg; Holo The Sage Wolf; Archie Cobbs; amber-dev
Betreff: Re: [External] : AW: Frozen objects?

 

I think const is a pretty fine concept, the confusion in c++ primarily comes
from it's confusing syntax and having multiple meanings like const member
functions.

A conversion from const to non const just makes no sense. You can use every
non const object like a const one but never the other way around. 

 

I prefer the inverted rust equivalent "mut" more as it makes the point more
clear. If you share a mutable reference you expect the recipient to mutate
your data, if you pass an immutable reference you can be ensured the
recipient won't change your data. 

 

It's just a contract rather or not some value can be mutated and rather or
not a method requires to mutate it's parameters.

 

In java we currently are stuck with exception throwing views, documentation
and defensive copies. 

 

I'm not sure rather adding an internal mutability system afterwards is
possible or a good idea. Especially old libraries would require some sort of
const cast to be usable. Which would undermine the certainty such a system
provides.

 

Best regards

RedIODev

 

 

On Wed, Dec 20, 2023, 17:58 Dan Heidinga <dan.heidinga at oracle.com> wrote:

C++ "const" is a bit of a mess.  It's not only a local property that
prevents writes to the reference; it's also a viral property that infects
the type system.  Instead of dealing with a single type ("X"), we now have
two ("X", "const X") with a 1-way conversion from "X -> const X" but no
conversion back (Let's not talk about const_cast's undefined behaviour..).
Now methods need to be defined to take either an X or a const X parameter
and need to flow the const through to all their callers.

 

But that's not all - now we need to be able to mark virtual methods to
declare if the receiver is const or not.  And to mark return types as const
or not.

 

There's a pretty massive cost to the user's mental model and to the language
as well as producing on-going compatibility problems (is adding or removing
"const" modifiers binary compatible? Source compatible?) for library
evolution.

 

Syntactic sugar to indicate "I won't write to this" doesn't really pay its
way.  The costs are quite high.

 

From: Markus Karg <markus at headcrashing.eu>
Date: Wednesday, December 20, 2023 at 5:32 AM
To: 'Holo The Sage Wolf' <holo3146 at gmail.com>
Cc: Dan Heidinga <dan.heidinga at oracle.com>, 'Archie Cobbs'
<archie.cobbs at gmail.com>, 'amber-dev' <amber-dev at openjdk.org>
Subject: [External] : AW: Frozen objects?

C++ ("const") does not freeze the memory region at all, and it does not need
to (and hence is quite fast at runtime as it does not even need to check the
access). The compiler simply rejects to compile the attempt to write via
read-only references. That would be sufficient for most cases. Freezing
objects is a different idea, and only needed in side cases. So I would plea
for introducing compile-time read-only references first, as it is the lower
hanging fruit.

-Markus

 

 

Von: Holo The Sage Wolf [mailto:holo3146 at gmail.com] 
Gesendet: Dienstag, 19. Dezember 2023 14:18
An: Markus Karg
Cc: Dan Heidinga; Archie Cobbs; amber-dev
Betreff: Re: Frozen objects?

 

How do you freeze a memory region without talking about freezing objects?

 

Unless your data is flat (so only value classes, primitives and arrays, 2 of
which won't benefit from freezing) the only way to have freezing something
that is enforced at compile time you must talk about objects.

On Tue, 19 Dec 2023, 10:04 Markus Karg, < <mailto:markus at headcrashing.eu>
markus at headcrashing.eu> wrote:

I wonder why we discuss about freezing *objects* (which needs time) but not
simply freezing *references* (like `const` does in C++)?

-Markus

 

 

Von: amber-dev [mailto: <mailto:amber-dev-retn at openjdk.org>
amber-dev-retn at openjdk.org] Im Auftrag von Dan Heidinga
Gesendet: Montag, 18. Dezember 2023 16:04
An: Archie Cobbs; amber-dev
Betreff: Re: Frozen objects?

 

Let me throw out one other concern: races.  The invariant frozen objects
want is that the application and runtime can trust they will never be
mutated again.  Unfortunately, if the object is published across threads
before it is frozen, then that invariant is very difficult and expensive to
maintain.

 

If two threads, A & B, both have references to the object and thread A
freezes it, B may still be publishing writes to it that A only observes
later.  To ensure the right JMM happens-before relationship for fields of
Freezable objects, both reads and writes would need to be more expensive
(volatile semantics?) until a thread could validate the object it was
operating on was frozen.

 

Freezing is not just a free set of unexplored optimizations.  There're also
new costs associated with it across the runtime (field read/write,
profiling, etc). 

 

--Dan

 

From: amber-dev <amber-dev-retn at openjdk.org> on behalf of Archie Cobbs
<archie.cobbs at gmail.com>
Date: Saturday, December 16, 2023 at 12:33 PM
To: amber-dev <amber-dev at openjdk.org>
Subject: Frozen objects?

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:

o    C: Any contiguous memory region that has a language name/identification

o    Java: At most 64 bits at a time (*) and arrays are not included

o    Advantage: C

.         Enforcement:

o    C: Enforced only by the compiler (mostly)

o    Java: Enforced by the compiler and at runtime

o    Advantage: Java

.         Dynamic Application:

o    C: Yes

o    Java: No

o    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

o    (*) Put frozen objects into a read-only region of memory to eliminate
mutation checks

o    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/20231221/61072168/attachment-0001.htm>


More information about the amber-dev mailing list