On why we have ForeignPtr

Unfortunately it isn't possible to add a finalizer to a normal Ptr a. We already have a generic finalization mechanism: see the Weak module in package lang. But the only reliable way to use finalizers is to attach one to an atomic heap object - that way the compiler's optimiser can't interfere with the lifetime of the object.

The Ptr type is really just a boxed address - it's defined like

data Ptr a = Ptr Addr#

where Addr# is an unboxed native address (just a 32- or 64- bit word). Putting a finalizer on a Ptr is dangerous, because the compiler's optimiser might remove the box altogether.

ForeignPtr is defined like this

data ForeignPtr a = ForeignPtr ForeignObj#

where ForeignObj# is a *boxed* address, it corresponds to a real heap object. The heap object is primitive from the point of view of the compiler - it can't be optimised away. So it works to attach a finalizer to the ForeignObj# (but not to the ForeignPtr!).

There are several primitive objects to which we can attach finalizers: MVar#, MutVar#, ByteArray#, etc. We have special functions for some of these: eg. MVar.addMVarFinalizer.

So a nicer interface might be something like

class Finalizable a where
   addFinalizer :: a -> IO () -> IO ()

instance Finalizable (ForeignPtr a) where ...
instance Finalizable (MVar a) where ...

So you might ask why we don't just get rid of Ptr and rename ForeignPtr to Ptr. The reason for that is just efficiency, I think.

Last modified: Wed Sep 26 09:49:37 BST 2001