ForeignPtr's - why can't they be passed directly to foreign functions?

Brian Hulley brianh at metamilk.com
Wed Mar 15 12:01:48 EST 2006


Simon Marlow wrote:
> Brian Hulley wrote:
>
>> I've got the beginnings of an API for a GUI system as follows:
> ...
>> addTop :: ForeignPtr (Window a) -> IO ()
>> addTop w = withForeignPtr w duma_addTop
>>
>> This works, but it seems a bit of a pain to have to manually convert
>> between ForeignPtr's and Ptr's all the time.
>> In particular, for the definition of addTop, I tried:
>>
>> foreign import ccall "duma_addTop" addTop :: ForeignPtr (Window a)
>> -> IO ()
>
> This is the way it used to be in GHC before the FFI.  In the FFI we
> moved to withForeignPtr instead.  IIRC, the motivation was something
> along these lines:
>
>  - allowing ForeignPtr to be passed directly to a foreign function
>    implies some magic that happens at the point of the foreign call
>    to convert the ForeignPtr to a Ptr.
>
>  - there also has to be some magic to ensure that the ForeignPtr
>    couldn't be finalized until the call returns.  This amounted to
>    adding a touch# primitive to keep the ForeignPtr alive over the
>    call. So internally the compiler was doing something like
>    withForeignPtr anyway.  This behaviour is quite hard to explain in
>    the spec, withForeignPtr is much simpler.


The above two things were what I was expecting the compiler to do for me 
instead of me having to manually write a wrapper function in Haskell using 
withForeignPtr for each wrapper function for each foreign function...

>
>  - We wanted withForeignPtr anyway, to avoid having to duplicate all
>    the marshalling operations that operate on Ptr.
>
> So, given that we wanted withForeignPtr anyway, there was no need to
> also have the compiler do its internal magic to allow ForeignPtr to be
> used as an FFI argument.  Also, this means GHC doesn't need a
> primitive ForeignPtr type (the primitive Ptr type is enough).

Would it be possible to just treat ForeignPtr in foreign types as syntactic 
sugar ie

         foreign import ccall foo :: ForeignPtr a -> IO ()

would just be syntactic sugar for:

         foreign import ccall "foo" foo' :: Ptr a -> IO ()

         foo :: ForeignPtr a -> IO ()
         foo x = withForeignPtr x foo'

The re-writing could be done at an early stage so that you'd still only need 
to deal with marshalling Ptr, but would save the user from having to 
manually create these extra wrappers, and would also give a simple way of 
explaining the meaning of a ForeignPtr argument in a foreign function type.

>
> Later on, we discovered that the withForeignPtr interface enables a
> much more efficient representation of ForeignPtr.  This is coming in
> GHC 6.6.

Every cloud has a silver lining! :-)))

Thanks, Brian. 



More information about the Glasgow-haskell-users mailing list