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:
> maybeString <- maybeNull peekCString ptr
Yes, let's use `maybeNull' and Sven's `maybeNothing'.
More information about the FFI