So I've been mulling over some automatic memory management ideas lately - specifically, I've been looking at implementing a memory manager based on reference counting. Of course, everyone knows that circular references kill naive reference counting. The solution: weak references. Personally, I hate using weak references in this way (there are other more intuitive ways of dealing with this, via cycle detection), but it got me thinking: where else could a weak reference be useful?
I figure that there must be some reason they exist, especially in languages with tracing garbage collection, which do not suffer from the cyclic reference pitfall (C# and Java are the ones I'm familiar with, and Java even has three kinds of weak references!). When I've tried to find some solid use-cases for them, though, I pretty much just got ideas like "Use them to implement caches" (I've seen that a few times on SO). I don't like that either, since they rely on the fact that a tracing GC will likely not collect an object immediately after it's no longer strongly referenced, except in low-memory situations. These kinds of cases are absolutely invalid with reference counting GC since an object is destroyed immediately after it is no longer referenced (except possibly in the case of cycles).
But that really leaves me wondering: How can a weak reference possibly be useful? If you can't count on it referencing an object, and its not needed for things like breaking cycles, then why use one?
Event handlers are a good use case for weak references. The object that fires events needs a reference to the objects to invoke event handlers on, but you typically don't want the event producer's reference holding to prevent the event consumers from being GC'd. Rather, you'd want the event producer to have a weak reference, and it would then be responsible for checking whether the referenced object was still present.