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