Let's get this finished

Simon Marlow simonmar at microsoft.com
Mon Jan 15 04:54:24 EST 2001

> I am all for moving the old CString routines to
> UnsafeCString, but that might annoy George and others who
> still have code importing the old CString.
> The old code contains cruft like
>     fill arr n [] =
> 	_casm_ ``((PP_)%0)[%1] = NULL;'' arr n
>     fill arr n (x:xs) = do
> 	barr <- packStringIO x
>         _casm_ ``((PP_)%0)[%1] = (P_)%2;'' arr n barr
> 	fill arr (n+1) xs
> which doesn't make much sense keeping around with the new
> FFI stuff in place.

It doesn't even look like it works!  If I'm reading the above code
correctly, it seems to build a ByteArray in which each element is a
pointer to another ByteArray, so if any of the arrays moves you're
hosed.  The Posix library uses it to implement exec.  George, are you
using it at all?

Most uses of unpackCString and friends can be replaced with peekCString
(CStrings from a foreign function are bound to be Ptr CChar).  For
packString, I've been using the following interface instead (in

	data UnsafeCString
	withUnsafeCString :: String -> (UnsafeCString -> IO a) -> IO a

where an UnsafeCString is valid only in an argument position of an
unsafe foreign import.

Would anyone object to adding these to CString?

> As 4.08.2 will still have the old interfaces, one possible
> route might be a more radical step for the first GHCi
> release (which will break all kinds of things anyway, I am
> sure :-}  We could collect all the old interfaces (I guess,
> there are other modules beside CString that can be phased
> out) in a new module "LangDeprecated" where we maybe even
> redefine the old routines in terms of the new ones.  Code
> using the old interfaces can, then, just import
> LangDeprecated until the code gets revised, but it is clear
> that the old interfaces will vanish one day.

Sounds reasonable, but a lot of hassle to get right.  I'm not in favour
of hassle purely for the purposes of deprecated interfaces :)

> Moreover, as soon as the unicode stuff gets in, all the old
> C-style string handling will be wrong anyway.
> As for bytearrays: AFAIK the only reason for using byte
> arrays over malloc is efficiency.  So, that makes them, I
> think, mainly interesting for allocating temporary storage,
> which is maybe even more critical for routines that need
> pointers to storage as out parameters to C routines doing
> little work.  This is actually more critical for routines
> handling small data items like ints than for strings.  So,
> we would like to have something like
>   with[Object]Unsafe   :: Storable a => a -> (Ptr a -> IO b) -> IO b
>   withArrayUnsafe      :: Storable a =>      [a] -> (Ptr a -> 
> IO b) -> IO b
>   withArray0Unsafe     :: Storable a => a -> [a] -> (Ptr a -> 
> IO b) -> IO b
>   withCStringUnsafe    :: String -> (CString -> IO a) -> IO a
>   withCStringLenUnsafe :: String -> (CStringLen -> IO a) -> IO a
> However, the real problem here is that if we want to use
> `ByteArray' instead of `Ptr', the types have to change and
> it is not H98 anymore.  So, the problem is getting the
> pointer from the allocation to the C function without moving
> it. *sigh*

I still can't think of a good way to do this in general.  Perhaps
enhancing the garbage collector so that it could "pin" objects - but
you've still got the problem of keeping the lifetime of the ByteArray in
sync with the Ptr.


More information about the FFI mailing list