Let's get this finished

Manuel M. T. Chakravarty chak at cse.unsw.edu.au
Fri Jan 5 10:24:00 EST 2001


Simon Marlow <simonmar at microsoft.com> wrote,

> > - MarshalString: 
> >     Most people seem to be of the opinion that we have to
> >     handle strings specially due to Unicode conversion
> >     requirements.  So, this is were string marshalling goes.
> 
> I've been wondering whether we should have something like
> 
> 	newtype CString = CString (Ptr CChar)
> 
> which would allow GHC to replace the representation with a ByteArray
> leading to a much more efficient implementation of withCString.  There
> are other reasons why having a special CString type might be a good
> idea: a C string really is more than just a pointer to char, it is an
> array with a zero terminator and is specified in some kind of encoding.
> Having a special CString type would provide more type safety.
> 
> One problem with the optimisation is that GHC can't handle ByteArrays
> being *returned* from a foreign function.

I think that this is a good idea.  Especially, because of
the encoding business, Strings are special and it is better
to make this explicit in the types.

Actually, given this unicode mess, how are we supposed to
handle individual `Char's?  A Haskell `Char' may expand to a
sequence of 8bit `char's.  That's a problem when the C side
only expects a `char' and not a `*char'.

> > - MarshalConv: 
> >     The C2HS IntConv, BoolConv, etc classes.  Marcin just
> >     uses `fromIntegral' here, but I think that this is too
> >     limited - eg, it doesn't handle Bool.
> 
> Could you explain the motivation for these?  I can see the need for some
> way to convert Bool<=>CInt (which is defined by ISO C), but can't the
> others be just fromIntegral?

One reason for extra functions is that we might want to
handle overflows differently.  I think, the Haskell report
doesn't specify what happens in case of an overflow.  In a
binding, I can imagine that I want to abort in case of
overflows during testing and in production code truncate the
values.

Furthermore, I have 

  instance IntConv Char where
    cToInt   = ord
    cFromInt = chr

> > Moreover,
> >     soemthing along the C2HS ToAddr/FromAddr classes, but it
> >     probably makes to have `stdArrayPtr' etc as additional
> >     member functions (this is similar to the newXXX routines
> >     that are in MarshalUtils now, but with additional
> >     overloading).  Furthermore, Marcin-syle withXXX routines
> >     would fo here.
> 
> I'm not sure how ToAddr/FromAddr would work.  From looking at C2HS, they
> seem to provide a consistent interface to marshalling that is specific
> to a given Haskell type.  I haven't found a need for something like this
> in my own code yet, so again could you motivate?

The member function `stdAddr' from `ToAddr' is similar to
MarshalUtils' `new' and `addrStdKeep' (and the derived
`addrStd') are the matching deallocation routine (which
MarshalUtils doesn't have) - the withXXX routines combine
the two.  Now, the current routines in MarshalUtils are
overloaded via `Storable', which works fine for the
primitives (in fact C2HS uses a default method for the
primitives).  It becomes interesting for more complex types.

For example, remember the case where Marcin had to store a
nullFunPtr on the C side and explicitly test for it before
calling freeHaskellFunPtr.  I think, it was Malcolm who
argued that Marcin should better use `Maybe (FunPtr a)' on
the Haskell side.  One reason that Marcin didn't do that
might be that he didn't have ToAddr/FromAddr, but only
functions overloaded via `Storable'.  I use

  instance ToAddr a => ToAddr (Maybe a) where
    stdAddr Nothing  = nullAddr
    stdAddr (Just x) = stdAddr x

  instance FromAddr a => FromAddr (Maybe a) where
    addrStdKeep addr | addr == nullAddr = return Nothing
		     | otherwise	= do
					    x <- addrStdKeep addr
					    return $ Just x

This transparently handles the `Maybe' representation for
NULL pointers, without cluttering the marshalling code with
special code for `Maybe'.  I also have a special case for
`String's.  Moreover, a binding author can add other
instances for binding specific types.  This happens, for
example, in the GDK binding - however, there arguably
overloading `Storable' would have been sufficient.

It might be sufficient to have one additional class instead
of two (at least, I don't see anymore why I originally used
two).

Cheers,
Manuel




More information about the FFI mailing list