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 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?
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. Cheers, Simon
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
On Mon, 15 Jan 2001, Simon Marlow wrote:
data UnsafeCString withUnsafeCString :: String -> (UnsafeCString -> IO a) -> IO a
where an UnsafeCString is valid only in an argument position of an unsafe foreign import.
Much of the conversion stuff would have to be done in a different way. An additional internal interface to conversions implemented in C (with ByteArrays instead of Ptrs), pointer arithmetic moved from Haskell to C, and in future hard to mix with Handle I/O done on Ptrs. All because there is no safe way to safely get a Ptr to a ByteArray to be used in Haskell.
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.
Lifetime is not a problem: withByteArray :: ByteArray -> (Ptr a -> IO b) -> IO b (And now we know that the ByteArray type should be parametrized!) This begins looking similarly to ForeignPtr from the outside. -- Marcin 'Qrczak' Kowalczyk
participants (3)
-
Manuel M. T. Chakravarty -
Marcin 'Qrczak' Kowalczyk -
Simon Marlow