I think we all agree now that malloc & friend can be written in H98 + FFI, so the only question is how they should be implemented in hslibs. The variant which uses local definitions instead of pattern type signatures is nicer IMHO because it *is* H98 and given GHC's optimizations, it doesn't make any performance difference. In general we should make hslibs as H98-conforming as possible and remove most GHCisms. For performance there's always #ifdef (well, at least if we consider piping Haskell sources through cpp as "standard"/H98). Manuel's MarshalXXX family look nice, but I'd like to summarize what exactly should go into what module, marking places which probably need more thoughts/discussions with `!!!!!': -- MarshalAlloc ------------------------------------------------------ malloc :: Storable a => IO (Ptr a) mallocBytes :: Int -> IO (Ptr a) alloca :: Storable a => (Ptr a -> IO b) -> IO b allocaBytes :: Int -> (Ptr a -> IO b) -> IO b reallocBytes :: Ptr a -> Int -> IO (Ptr a) free :: Ptr a -> IO () -- MarshalArray ------------------------------------------------------ mallocArray :: Storable a => Int -> IO (Ptr a) mallocArray0 :: Storable a => Int -> IO (Ptr a) allocaArray :: Storable a => Int -> (Ptr a -> IO b) -> IO b allocaArray0 :: Storable a => Int -> (Ptr a -> IO b) -> IO b reallocArray :: Storable a => Ptr a -> Int -> IO (Ptr a) reallocArray0 :: Storable a => Ptr a -> Int -> IO (Ptr a) !!!!! The current MarshalUtils uses !!!!! peekArray :: Storable a => Ptr a -> Int -> IO [a] !!!!! but the signature below looks more consistent with peekArray0: peekArray :: Storable a => Int -> Ptr a -> IO [a] peekArray0 :: (Storable a, Eq a) => a -> Ptr a -> IO [a] pokeArray :: Storable a => Ptr a -> [a] -> IO () pokeArray0 :: Storable a => a -> Ptr a -> [a] -> IO () withArray :: Storable a => [a] -> (Ptr a -> IO b) -> IO b withArray0 :: Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b newArray :: Storable a => [a] -> IO (Ptr a) newArray0 :: Storable a => a -> [a] -> IO (Ptr a) -- MarshalString ----------------------------------------------------- !!!!! I'm with Marcin here: Let's keep things simple and do not !!!!! provide an opaque type CString here. We can't guess all !!!!! possible uses, so a type synonym would be the right thing !!!!! here. Using a pointer/length combo is quite common, too, !!!!! so this deserves another type synonym. Note that some !!!!! functions below look a bit strange, but symmetry rulez! :-) !!!!! Charset conversions are a diff{erent,icult} story and should !!!!! be handled by a separate module, so only the well-known !!!!! ignore-the-upper-half variants are given here. type CString = Ptr CChar type CStringLen = (CString, Int) mallocCString :: String -> IO CString mallocCStringLen :: String -> IO CStringLen peekCString :: CString -> IO String peekCStringLen :: CStringLen -> IO String pokeCString :: CString -> String -> IO () pokeCStringLen :: CStringLen -> String -> IO () withCString :: String -> (CString -> IO a) -> IO a withCStringLen :: String -> (CStringLen -> IO a) -> IO a newCString :: String -> IO CString newCStringLen :: String -> IO CStringLen -- MarshalError ------------------------------------------------------ !!!!! Haven't thought very deeply about this, but Marcin's QErrors !!!!! probably looks OK after a little polishing (use strerror, !!!!! provide a more complete throwXXX family, ...). And remember: !!!!! errno *is* a thread-local thing. :-) -- MarshalConv ------------------------------------------------------- !!!!! I can't see a compelling reason for this module, neither what !!!!! exactly should belong here. ISO C defines a mapping to 0/1, !!!!! which can easily be captured by fromBool/toBool (in MarshalUtils !!!!! below). Maybe is handled there, too. -- MarshalUtils ------------------------------------------------------ fromBool :: Num a => Bool -> a fromBool = fromIntegral . fromEnum toBool :: Num a => a -> Bool toBool = (/= 0) withObject :: Storable a => a -> (Ptr a -> IO b) -> IO b new :: Storable a => a -> IO (Ptr a) !!!!! Example usages: !!!!! do ... !!!!! mbInt <- maybeNull peek ptr1 !!!!! mbString <- maybeNull peekCString ptr2 !!!!! ..... !!!!! maybeNothing withObject Nothing $ \ptr -> ... !!!!! maybeNothing withCString (Just "foo!") $ \ptr -> ... !!!!! !!!!! Does anybody have better names for these two functions? !!!!! They sound OK for me, but I'm not a native speaker... maybeNull :: (Ptr a -> IO b) -> Ptr a -> IO (Maybe b) maybeNull f ptr | ptr == nullPtr = return Nothing | otherwise = liftM Just $ f ptr maybeNothing :: (a -> (Ptr b -> IO c) -> IO c) -> (Maybe a -> (Ptr b -> IO c) -> IO c) maybeNothing = maybe ($ nullPtr) copyArray :: Storable a => Ptr a -> Ptr a -> Int -> IO () copyBytes :: Ptr a -> Ptr a -> Int -> IO () moveArray :: Storable a => Ptr a -> Ptr a -> Int -> IO () moveBytes :: Ptr a -> Ptr a -> Int -> IO () !!!!! Do we really need this? indexPtr :: Storable a => Ptr a -> Int -> Ptr a As Manuel already wrote it's a good idea to leave C2HS's marshX routines out and to re-export all the modules above, but should this be done via a new module Marshal or should Foreign do this? Should Marshal re-export Foreign or vice-versa? Hmmm... And just a final topic which really should be settled: "Marshal" or "Marshall"?? :-} Cheers, Sven