Let's get this finished

Marcin 'Qrczak' Kowalczyk qrczak at knm.org.pl
Sat Jan 6 07:47:38 EST 2001

Sat, 06 Jan 2001 00:24:14 +0100, Sven Panne <Sven.Panne at informatik.uni-muenchen.de> pisze:

> For performance there's always #ifdef (well, at least if we
> consider piping Haskell sources through cpp as "standard"/H98).

hsc2hs used instead of cpp provides #ifdef too, and avoids lexical
analysis of Haskell source as C source.

>     !!!!! 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]


>    !!!!! 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.

I think the conversion story should proceed thus:

- For now the implementation will not do any conversion.

- At some point of time all IO and C string handling will switch
  to do the conversion, keeping the same interface for the case of
  the default encoding, and providing additional means for using
  different encodings.

It is important do introduce the conversion in all places at once,
otherwise reading a filename containing non-ASCII characters from
a file and using it to open another file will fail.

Unfortunately it means that parts of the FFI functionality will have
to go to ghc's lib/std, to properly handle strings and I/O in standard
libraries. The more of convenience functions will be kept in hslibs,
the less fun will be to fix standard libraries.

The interface of string handling functions must allow that move
in future without incompatible changes. We can't have separate
mallocCString and pokeCString after the conversion switch, because
the size depends on the contents, because a conversion can change
the length. So we should not provide them now either.

When someone really wants to use mallocCString and pokeCString now
(knowing that there is a little point of doing that in the case of
conversions), he can use mallocArray0 and pokeArray0, after casting
characters of the string to [CChar].

>    !!!!! 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.  :-)

A little warning: strerror will want to translate strings, and
even do the conversion (the result of strerror is in the default
byte encoding). I had a module dependency loop when I wanted to use
strerror and at the same time handle errno in iconv's wrapper.

> -- MarshalUtils ------------------------------------------------------
>     fromBool   :: Num a => Bool -> a
>     fromBool = fromIntegral . fromEnum

I think that
    fromBool :: Num a => Bool -> a
    fromBool False = 0
    fromBool True  = 1
is more clear (and easier to compile efficiently) :-)

>     !!!!!       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...

maybeNothing looks very cryptic for me, but I don't have a better

>     !!!!! Do we really need this?
>     indexPtr         :: Storable a => Ptr a -> Int -> Ptr a

I used it once in Libgr, 3 times in QString and 5 times in
conversions. I would definitely keep it. Perhaps the name movePtr
would be better.

Let me repeat a proposal of two functions for MarshalUtils
(better names are welcome):

    sequenceCont :: [(a -> res) -> res] -> ([a] -> res) -> res
    sequenceCont []     cont = cont []
    sequenceCont (f:fs) cont = f (\x -> sequenceCont fs (\xs -> cont (x:xs)))

    mapCont :: (a -> (b -> res) -> res) -> [a] -> ([b] -> res) -> res
    mapCont f = sequenceCont . map f

    mapCont withCString a_list_of_Haskell_strings $
        \a_list_of_C_string_pointers ->

Without them one has to write an explicit recursive function each
time for passing an array of things-to-be-allocated-on-the-stack to
a C function.

I would like to write
    instance Monad (/\a. (a -> res) -> res)
instead of them. Unfortunately it's not possible.

 __("<  Marcin Kowalczyk * qrczak at knm.org.pl http://qrczak.ids.net.pl/
  ^^                      SYGNATURA ZASTÊPCZA

More information about the FFI mailing list