Alternative Design for Finalisation

Ashley Yakeley ashley@semantic.org
Thu, 20 Sep 2001 04:08:40 -0700


If ForeignPtrs work the way I think they do, then I'm surprised they're 
designed as pointers. I believe the 'pointer' functionality is orthogonal 
to the 'finalisable' functionality and should be separated like this:

--
data Finalisable a	-- abstract handle to finalisable object
instance Eq (Finalisable a);
newFinalisable      :: a             -> IO () -> IO (Finalisable a);
addFinaliser        :: Finalisable a -> IO () -> IO (); 
withFinalisable     :: Finalisable a -> (a -> IO b) -> IO b;
touchFinalisable    :: Finalisable a -> IO ();
finalisableContents	:: Finalisable a -> a;

type ForeignPtr a = Finalisable (Ptr a);
newForeignPtr          :: Ptr a        -> IO () -> IO (ForeignPtr a);
newForeignPtr = newFinalisable;
addForeignPtrFinalizer :: ForeignPtr a -> IO () -> IO () ;
addForeignPtrFinalizer = addFinaliser;
withForeignPtr         :: ForeignPtr a -> (Ptr a -> IO b) -> IO b;
withForeignPtr = withFinalisable;
touchForeignPtr        :: ForeignPtr a -> IO ();
touchForeignPtr = touchFinalisable;
foreignPtrToPtr	       :: ForeignPtr a -> Ptr a;
foreignPtrToPtr = finalisableContents;
--

I am slightly bothered by the type of 
finalisableContents/foreignPtrToPtr. Shouldn't it be in the IO monad? 
Apart from 'finalisers already run' risk, is it safe?

But 'castForeignPtr' would not be definable, unless you wanted to do 
something like this:

--
instance Functor Finalisable;
castForeignPtr	        :: ForeignPtr a -> ForeignPtr b;
castForeignPtr = fmap castPtr;
--

...which I don't believe is appropriate.

The only time when ForeignPtrs act like Ptrs is when they are used as FFI 
arguments. But I believe that's purely syntactic sugar for 
withForeignPtr, and would be no loss.

--
foreign import "foo" fooFP :: ForeignPtr a -> IO ();
foreign import "foo" fooP  :: Ptr a -> IO ();

fooFP' :: ForeignPtr a -> IO ();
fooFP' fp = withForeignPtr fp fooP;
--


-- 
Ashley Yakeley, Seattle WA