The Module Signature

module Weak ( Weak, -- abstract -- instance Eq (Weak v) mkWeak, -- :: k -> v -> IO () -> IO (Weak v) deRefWeak -- :: Weak v -> IO (Maybe v) -- Not yet implemented -- finalise -- :: Weak v -> IO () -- replaceFinaliser -- :: Weak v -> IO () -> IO () mkWeakPtr -- :: k -> IO () -> IO (Weak k) mkWeakPair -- :: k -> v -> IO () -> IO (Weak (k,v)) addFinaliser -- :: k -> IO () -> IO () addForeignFinaliser -- :: ForeignObj -> IO () -> IO () ) where Weak pointers

In general terms, a weak pointer is a reference to an object that is not followed by the garbage collector --- that is, the existence of a weak pointer to an object has no effect on the lifetime of that object. A weak pointer can be de-referenced to find out whether the object it refers to is still alive or not, and if so to return the object itself. Weak pointers are particularly useful for caches and memo tables. To build a memo table, you build a data structure mapping from the function argument (the key) to its result (the value). When you apply the function to a new argument you first check whether the key/value pair is already in the memo table. The key point is that the memo table itself should not keep the key and value alive. So the table should contain a weak pointer to the key, not an ordinary pointer. The pointer to the value must not be weak, because the only reference to the value might indeed be from the memo table. So it looks as if the memo table will keep all its values alive for ever. One way to solve this is to purge the table occasionally, by deleting entries whose keys have died. The weak pointers in this library support another approach, called The simple interface

mkWeakPtr :: a -> IO () -> IO (Weak a) deRefWeak :: Weak a -> IO (Maybe a) addFinaliser :: a -> IO () -> IO () addFinaliser :: a -> IO () -> IO () addFinaliser v f = do { mkWeakPtr v f; return () } The effect of Every finaliser will eventually be run, exactly once, either soon after the object dies, or at the end of the program. There is no requirement for the programmer to hold onto the weak pointer itself; finalisation is completely unaffected by whether the weak pointer itself is alive. There may be multiple weak pointers to a single object. In this case, the finalisers for each of these weak pointers will all be run in some arbitrary order, or perhaps concurrently, when the object dies. If the programmer specifies a finaliser that assumes it has the only reference to an object (for example, a file that it wishes to close), then the programmer must ensure that there is only one such finaliser. The storage manager attempts to run the finaliser(s) for an object soon after the object dies, but promptness is not guaranteed. (What is guaranteed is that the finaliser will eventually run, exactly once.) At the moment when a finaliser is run, a call to A finaliser may contain a pointer to the object, but that pointer will not keep the object alive. For example: f :: Show a => a -> IO a f x = addFinaliser x (print (show x)) Here the finaliser A finaliser may even resurrect the object, by (say) storing it in some global data structure. The general interface

The mkWeak :: k -> v -> IO () -> IO (Weak v) deRefWeak :: Weak a -> IO (Maybe a) However, mkWeakPtr :: a -> IO () -> IO (Weak a) mkWeakPtr v f = mkWeak v v f These more general weak pointers are enough to implement memo tables properly. A precise semantics

The above informal specification is fine for simple situations, but matters can get complicated. In particular, it needs to be clear exactly when a key dies, so that any weak pointers that refer to it can be finalised. Suppose, for example, the value of one weak pointer refers to the key of another...does that keep the key alive? The behaviour is simply this: If a weak pointer (object) refers to an Finalisation means (a) arrange that subsequent calls to This behaviour depends on what it means for a key to be reachable. Informally, something is reachable if it can be reached by following ordinary pointers from the root set, but not following weak pointers. We define reachability more precisely as follows A heap object is reachable if: It is directly pointed to by a reachable object, other than a weak pointer object. It is a weak pointer object whose key is reachable. It is the value or finaliser of an object whose key is reachable. Notice that a pointer to the key from its associated value or finaliser does not make the key reachable. However, if the key is reachable some other way, then the value and the finaliser are reachable, and so, therefore, are any other keys they refer to directly or indirectly. Finalisation for foreign objects

A foreign object is some data that lives outside the Haskell heap, for example some ), and we must retain the invariant that ).