Let's get this finished

Manuel M. T. Chakravarty chak at cse.unsw.edu.au
Sat Jan 6 06:30:47 EST 2001

"Marcin 'Qrczak' Kowalczyk" <mk167280 at zodiac.mimuw.edu.pl> wrote,

> On Sat, 6 Jan 2001, Manuel M. T. Chakravarty wrote:
> > 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.
> I'm not sure if this is a good idea. I haven't seen convincing arguments
> yet. Let's keep it simpler.

The opinion trend for MarshalXXX seems to be clear: Keep it
simple.  So, ok, let's leave it out.

> > 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'.
> No library will be able to represent Char or wchar_t in a single char.

Sure.  C can choose between char and wchar_t, we only have
Char in Haskell.  That is what is bothering me.

> > > 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.
> We would need to use a different interface to signal the overflow. Some
> exception monad (Maybe or IO). These additional functions don't provide it
> anyway and I will stick with fromIntegral - the most natural Haskell's way
> of converting integers.

That's not what I meant.  When an overflow is encountered,
an `error' can be raised.  The point is that during
"testing" a binding, I want to see where overflows happen
and not just get a core dump later on.

Anyway, as I wrote earlier, let's drop MarshalConv.

> > 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.
> When there is more than one way to pass a complex type, I would just use
> separate functions if a Storable instance does not fit.
> I would represent a pointer to a C string as Ptr CChar in Haskell and use
> different functions for distinguishing what we want to do with it. Passing
> the string to C functions is not the only thing we might want to do with
> it - e.g. we could wish to realloc it, or work on [CChar] in Haskell, or
> convert it to an aray of bytes, or pass a pointer to the middle to a C
> function. IMHO it's better and less constraining to be explicit, keep the
> type and make approprate functions as needed. withCString is not that
> harder than toAddr. There are too many possible operations to express them
> in one overloaded function on different types.

I see your point, however, personally, I still prefer to
have overloading for the common cases (that what we want
most of the time when given a particular type) and use
explicit functions only for the exceptions.  That makes the
resulting code more readable in my opinion - as it contains
less clutter for the common case.  But I guess, this is a
matter of personal style.

> > 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'.
> ToAddr/FromAddr would not help here, unless they provided some
> appropriately overloaded variant of peek.

The definitions that I gave in my previous mail *do* help in
this case.  I use them myself in C2HS.

> [...]
> > This transparently handles the `Maybe' representation for
> > NULL pointers, without cluttering the marshalling code with
> > special code for `Maybe'.
> Passing Maybe as a maybe-null pointer is easy already:
>     maybe ($nullPtr) withCString maybeString $ \ptr -> ...
> For the other direction a single function could be added:
>     maybeNull :: (Ptr a -> IO b) -> Ptr a -> IO (Maybe b)
>     maybeNull f ptr
>         | ptr == nullPtr = return Nothing
>         | otherwise      = liftM Just (f ptr)
> Use it as such:
>     do
>         maybeString <- maybeNull peekCString ptr
>         ...

Yes, let's use `maybeNull' and Sven's `maybeNothing'.


More information about the FFI mailing list