Alternative Design for Finalisation

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
participants (1)
-
Ashley Yakeley