> > It certainly seems that all the choices are bad. > > The "obvious" choice is to simply say that WeakReference<Value> makes no > sense, in that it sidesteps the hard semantics questions.
It's an uncomfortable answer but it seems to provide the most defensible (and thus understandable) semantics for users. Values don't have an explicit lifetime and thus there is no way to tell when "this" copy of a value goes out of scope and can be collected. The object references (if any) held by the value are not a good proxy for its lifecycle - they can have either shorter or much longer life spans - and will make reasoning about when a WeakReference<Value> can be collected difficult for experts, let alone most users. > My fear is that this will cause new failures, where existing libraries that > toss objects into WHMs to cache derived results, will start to experience new > failures when the value types show up in the heap (after all, > WeakReference::new takes Object.) This may be a case where the WeakReference constructor needs to be updated to take an IdentityObject and the old constructor marked as @Deprecated? Which doesn't solve the immediate problem but helps justify adding a "fail-fast" check to all WeakReference constructors so that they throw an IllegalArgumentException if the referent isn't an IdentityObject. This won't avoid failures but it does make it very clear what went wrong rather than introducing "strange", hard to diagnose failures. > And we'll have to have something to tell those users, because they declared a > WeakHashMap<User, UserData>, and someone created a value subtype of User -- > which seems entirely valid. > > It is possible we could do something special with WHM, since it is layered > atop WR, but that still begs the question -- what? Starting from the conclusion that WeakReference<Value> is a meaningless entity, what are the options here? 1) Make it impossible to use a Value as a key in a WeakHashMap. ::put(key, value) & ::pulAll(Map m) will throw if a key is a Value object. ::containsKey(Object) will always be false if the Object is a ValueObject. This makes WeakHashMap unusable with Values. The semantics are clear but all existing uses of WeakHashMap will need to be adapted to defensively check for Values and do something (tbd) to avoid the exceptions. 2) Use strong references for Value keys in WeakHashMap. Treat each Value object used as a key in WeakHashMap as a strong reference. This means Value keys will never be removed and will keep their corresponding map value alive forever (or until explicitly removed). While this will allow WeakHashMaps to continue to be used as Maps for Values, it will break the contract for WHM and may introduce memory leaks into otherwise correct programs. 3) Pick some other object to act as the reference when using a Value key in a WHM. This is basically the solution we rejected for WeakReference<Value> and all the same problems apply here. It may allow existing code to "keep working" when it first deals with Values but introduces strange failure cases and difficult to reason about rules. It avoids exceptions but leaves the code doing the wrong thing with no way to tell. Anyone see another option here? --Dan