Type of newForeignPtr & addForeignPtrFinalizer

Adrian Hey ahey@iee.org
Sun, 7 Jul 2002 07:46:59 +0100


I have a feeling this may be a stupid question, but why are the
types of these..
 newForeignPtr          :: Ptr a -> IO () -> IO (ForeignPtr a)
 addForeignPtrFinalizer :: ForeignPtr a -> IO () -> IO ()
(second arg being the finalizer)

Won't a finaliser almost always take a pointer to the thing being
finalised as an argument? If so it would be more convienient
to have newForeignPtr..
 newForeignPtr :: Ptr a -> (Ptr a -> IO ()) -> IO (ForeignPtr a)
or maybe..
 newForeignPtr :: Ptr a -> (ForeignPtr a -> IO ()) -> IO (ForeignPtr a)

 addForeignPtrFinalizer :: ForeignPtr a -> (ForeignPtr a -> IO ()) -> IO ()

The first of these is easy to implement yourself I suppose..
 myNewForeignPtr :: Ptr a -> (Ptr a -> IO ()) -> IO (ForeignPtr a)
 myNewForeignPtr p fin = newForeignPtr p (fin p)

The second seems to require this bit of weirdness..
 myNewForeignPtr :: Ptr a -> (ForeignPtr a -> IO ()) -> IO (ForeignPtr a)
 myNewForeignPtr p fin = do
   newfp  <- newForeignPtr p (return ())
   addForeignPtrFinalizer newfp (fin newfp)
   return newfp

Unless I'm missing something, you have to use a pointless dummy
finaliser (return ()) to get a ForeignPtr to use as the argument
of the real finaliser.
The reason I ask is I've been trying to use C2HS recently to
produce a Haskell binding to GNU plot library, and have had
to do something very similar. The relevant bits of .chs file

-- Haskell: newtype Plotter = Plotter (ForeignPtr Plotter)
{#pointer *plPlotter       as Plotter       foreign newtype#}

-- Haskell: newtype PlotterParams = PlotterParams (ForeignPtr PlotterParams)
{#pointer *plPlotterParams as PlotterParams foreign newtype#}

-- Destructor for the plPlotter type.
-- C proto: int pl_deletepl_r (plPlotter *plotter);
-- Haskell: deletePlotter :: Plotter -> IO ()
{#fun unsafe pl_deletepl_r as deletePlotter
        {id `Plotter'} -> `()'			-- id as marshaller??

-- Create a new X Plotter
-- C proto: plPlotter* new_x_plotter (plPlotterParams* plotter_params);
-- Haskell: newXPlotter   :: PlotterParams -> IO Plotter
--          newXPLotter'_ :: PlotterParams -> IO (Ptr Plotter)
{#fun unsafe new_x_plotter as newXPlotter
        {id `PlotterParams'} -> `Plotter' marshalPlotter *
marshalPlotter :: Ptr Plotter -> IO Plotter
marshalPlotter p = do
 foreignPlotter <- newForeignPtr p (return ())
 let plotter = Plotter foreignPlotter
 addForeignPtrFinalizer foreignPlotter (deletePlotter plotter)
 return plotter

I suppose the thing that's worrying me most is will this work?
(I don't have enough done yet to find out). It seems overly
complicated to me, but I can't see any alternative to this
complexity. Am I using C2HS right? Have I missed something

Adrian Hey