Hi David, I think I didn't explain myself very clearly. My ideal default behavior would be to make WR a strong reference and print a warning.
Or, to be more specific, I hope its behavior is configurable (controlled by a parameter similar to --illegal-native-access). I would like it to have at least three modes of behavior: 1. allow: silently treat WR as a strong reference 2. warn: treat WR as a strong reference and emit a warning 3. deny: throw an IdentityException The default should be behavior 1 or 2, and only in the relatively distant future should we consider changing the default to 3. Glavo On Sat, Dec 13, 2025 at 6:40 AM David Alayachew <[email protected]> wrote: > I don't agree that #4 is the worst option -- in fact, I think it is the > best of the 4. Though, my opinion might change with a prototype to play > with. > > But regardless, I do agree that some sort of warning would be good. > Preferrably a JFR Event. Like Glavo said -- there are a lot of catch-all's > out there, so having the event **as well as** the exception sounds best to > me. > > On Fri, Dec 12, 2025, 4:17 PM Glavo <[email protected]> wrote: > >> Hi Brian, >> >> This answer was unexpectedly simple to me. >> >> Of course, I understand the common usage of WR. I clearly know that the >> semantics I mentioned, while allowing some code to work, do not align with >> the original intent of using WR in those contexts. >> >> However, I believe throwing an exception is the worst option—far worse >> than letting the WR turn into a strong reference. >> This is because users have long had the obligation to handle OOM; they >> can proactively trigger OOM for testing by reducing heap size or other >> means. >> In contrast, users have never had the obligation to handle >> IdentityException, nor any way to test it. As a result, an unexpected >> exception could lead the program into untested code paths. >> I even think throwing an exception is worse than directly letting the VM >> crash, because some catch blocks might silently swallow the >> IdentityException, making it much harder for users to understand why their >> program behaved abnormally. >> >> For me, a more ideal approach would be to print a warning by default when >> creating a WR for a value object—at least this would make it easier for >> developers to notice the issue. >> >> Glavo >> >> On Sat, Dec 13, 2025 at 2:39 AM Brian Goetz <[email protected]> >> wrote: >> >>> Indeed, many hours of discussion went into this decision. >>> >>> The basic problem is that all of the obvious answers are either >>> surprising or surprisingly expensive. We considered the following four >>> approaches: >>> >>> 1. Allow `new WR(value)`, which is cleared on birth. >>> 2. Allow `new WR(value)`, which is never cleared. >>> 3. Allow `new WR(value)`, which is cleared when all identities >>> reachable through the value are become weakly reachable. >>> 4. Throw, and encourage implementations that are built on WR (such as >>> WHM) to offer their own ways of dealing with values. >>> >>> You can readily see how (1) would not be what anyone expects. >>> >>> You are arguing for (2). While this initially seems credible, its >>> primary appeal is "yeah it's useless, but it won't break things that just >>> throw everything in a WHM". But it is actually worse than useless! The >>> purposes of WRs is to not unnecessarily pin things in memory. But a WR >>> that is never cleared does exactly that; if the referent holds identities, >>> then it effectively becomes a strong reference. >>> >>> (3) is a more principled answer, but is very expensive to implement, and >>> its still not clear that this is what people will expect. >>> >>> (4) is honest, if inconvenient. Given that the majority of uses of WR >>> are through higher-level constructs like WHM, which have more flexibility >>> to choose the semantics that is right for their more restricted domain, it >>> made sense to make this a WHM (and friends) problem than a WR problem >>> (given that there were no good answers at the WR level.) >>> >>> On 12/12/2025 10:02 AM, Glavo wrote: >>> >>> Hi, >>> >>> In the current draft of JEP 401, I saw the following statement: >>> >>> > The garbage collection APIs in java.lang.ref and java.util.WeakHashMap >>> do not allow developers to manually manage value objects in the heap. >>> > Attempts to create Reference objects for value objects throw >>> IdentityException at run time. >>> >>> We could clearly have pretended that all value objects exist forever and >>> are never collected, so that Reference or WeakHashMap would still work with >>> value objects. >>> Obviously, doing so would break far fewer existing codes, whereas having >>> them directly throw IdentityException would break a lot more code. >>> >>> As an analogy, I think this is very similar to ThreadLocal on virtual >>> threads. Although virtual threads make many use cases of ThreadLocal >>> low-performance and high-memory, >>> Project Loom did not outright forbid users from using ThreadLocal on >>> virtual threads, yet Project Valhalla chose to break this (admittedly >>> inefficient) writing style. >>> >>> I don’t understand why Project Valhalla made this choice. Has there been >>> any related discussion in the past? I’m really eager to know the reasoning >>> behind this decision. >>> >>> Glavo >>> >>> >>>
