Add a big warning to the documentation for Weak (#7250)
authorSimon Marlow <marlowsd@gmail.com>
Fri, 21 Sep 2012 15:11:20 +0000 (16:11 +0100)
committerSimon Marlow <marlowsd@gmail.com>
Fri, 21 Sep 2012 15:11:20 +0000 (16:11 +0100)
libraries/base/GHC/Weak.lhs
libraries/base/System/Mem/Weak.hs

index 93c4eac..e3109e1 100644 (file)
@@ -55,7 +55,7 @@ It is not guaranteed that a finalizer will eventually run, and no
 attempt is made to run outstanding finalizers when the program exits.
 Therefore finalizers should not be relied on to clean up resources -
 other methods (eg. exception handlers) should be employed, possibly in
-addition to finalisers.
+addition to finalizers.
 
 References from the finalizer to the key are treated in the same way
 as references from the value to the key: they do not keep the key
@@ -76,6 +76,24 @@ such finalizer.
 
 If there are no other threads to run, the runtime system will check
 for runnable finalizers before declaring the system to be deadlocked.
+
+WARNING: weak pointers to ordinary non-primitive Haskell types are
+particularly fragile, because the compiler is free to optimise away or
+duplicate the underlying data structure.  Therefore attempting to
+place a finalizer on an ordinary Haskell type may well result in the
+finalizer running earlier than you expected.  This is not a problem
+for caches and memo tables where early finalization is benign.
+
+Finalizers /can/ be used reliably for types that are created explicitly
+and have identity, such as @IORef@ and @MVar@.  However, to place a
+finalizer on one of these types, you should use the specific operation
+provided for that type, e.g. @mkWeakIORef@ and @addMVarFinalizer@
+respectively (the non-uniformity is accidental).  These operations
+attach the finalizer to the primitive object inside the box
+(e.g. @MutVar#@ in the case of @IORef@), because attaching the
+finalizer to the box itself fails when the outer box is optimised away
+by the compiler.
+
 -}
 data Weak v = Weak (Weak# v)
 
@@ -116,7 +134,7 @@ deRefWeak (Weak w) = IO $ \s ->
 finalize :: Weak v -> IO ()
 finalize (Weak w) = IO $ \s ->
    case finalizeWeak# w s of
-        (# s1, 0#, _ #) -> (# s1, () #) -- already dead, or no finaliser
+        (# s1, 0#, _ #) -> (# s1, () #) -- already dead, or no finalizer
         (# s1, _,  f #) -> f s1
 
 {-
index 4003a74..71b8446 100644 (file)
@@ -94,15 +94,10 @@ mkWeakPtr key finalizer = mkWeak key key finalizer
   when the key becomes unreachable).
 
   Note: adding a finalizer to a 'Foreign.ForeignPtr.ForeignPtr' using
-  'addFinalizer' won't work as well as using the specialised version
-  'Foreign.ForeignPtr.addForeignPtrFinalizer' because the latter
-  version adds the finalizer to the primitive 'ForeignPtr#' object
-  inside, whereas the generic 'addFinalizer' will add the finalizer to
-  the box.  Optimisations tend to remove the box, which may cause the
-  finalizer to run earlier than you intended.  The same motivation
-  justifies the existence of
-  'Control.Concurrent.MVar.addMVarFinalizer' and
-  'Data.IORef.mkWeakIORef' (the non-uniformity is accidental).
+  'addFinalizer' won't work; use the specialised version
+  'Foreign.ForeignPtr.addForeignPtrFinalizer' instead.  For discussion
+  see the 'Weak' type.
+.
 -}
 addFinalizer :: key -> IO () -> IO ()
 addFinalizer key finalizer = do