Yes, I stopped at choice "1" and didn't move past that. Glad to hear
you've been thinking about it. It sounds like a wrapper of some sort
will be the way forward for us. We can revisit as more use cases emerge
that might push the thinking for weak references for value objects in
one direction or another.
-- Kevin
On 8/3/2026 11:12 AM, Brian Goetz wrote:
I have two questions:
1. Has there been any discussion of allowing WeakReference (and the
corresponding JNI NewWeakGlobalRef) to accept value objects in a
future revision of the value objects feature? Obviously in this case,
the referent would never be cleared by GC, but it would allow common
code to be able to continue to function. There are some "gotchas"
here. For example, would such a reference ever be automatically
enqueued on a ReferenceQueue? If so, when and how would that work?
Indeed, we have discussed this! The first question is "what should
the semantics of WR(value) be". And there are actually at least three
reasonable answers, and the choice of which is the "most right" is not
as obvious as it might seem.
1. As you suggest, WR(value) is just never cleared.
2. A WR(value) is always immediately cleared.
3. A WR(value) can be cleared only when any identities held within it
are weakly reachable.
(1) is the first one everyone comes to, because it avoids cases like
the one you've encountered -- but doesn't really implement any sort of
weakness. (2) is justifiable but likely useless in most cases. (3) is
actually principled; it asks "could this value be reconstituted", and
that is only true if its fields can be reconstituted, which is always
true for pure values and true for identities if they are reachable.
But (3) is obviously very intrusive for the GC, and it is not obvious
how helpful in practice it is.
Since there is not an obviously "right and useful and reasonably
implementable answer", right now WRs just say "nope" when presented
with a value object.
2. What is the best advice for applications or libraries like JavaFX
to deal with this? The current approach we are considering is
described in [2] and [3], where we would create a
WeakReferenceWrapper class that either creates and stores a reference
(if the object has identity) or stores the object itself (if it is
either null or does not have identity). Its get method would return
either ref.get() or obj. Is there a better approach?
This is what we recommend for the time being; it simulates semantics
(1) above, but dumps the bookkeeping in your lap, which is obviously
not great.
Longer-term, we observe that many of the uses of WR are through
WeakHashMap, and it would be reasonable to specify a policy to the WHM
constructor that says what to do: throw, follow (1), follow (2), etc.
A WRWrapper could then offer the same set of choices. This would leave
WR in its current, simple state. I suspect there will never be one
answer that does what all applications expect of WR(value), which is
why a multiplicity of potential policies, implemented from outside of
WR, seems likely.