Simon Marlow <simonmar@microsoft.com> wrote,
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 ghc/lib/std/PrelCString):
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?
Fine by me, but IMHO we should really have similar routines for other types of objects, too.
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.
Can't we touch# the ByteArray until the function passed to the with combinator returns? That should do the trick. Cheers, Manuel