qforeign-0.62

Marcin 'Qrczak' Kowalczyk mk167280 at students.mimuw.edu.pl
Tue Nov 28 10:55:18 EST 2000


On Tue, 28 Nov 2000 malcolm-ffi at cs.york.ac.uk wrote:

> I'm with Manuel.  Module FFI/Foreign is already stable, and I object
> to adding things to it arbitrarily.  By all means make a new module
> with these functions, which I can see could be useful.  But please
> don't just allow "feature creep" over already-agreed specifications.

C string functions are necessary to exchange strings with C. Ok, they may
be put in CForeign, but without a common interface that will at some point
switch to proper charset handling it's impossible to correctly interface
to most C libraries.

> Once these newer features are settled, I look forward to seeing a
> portable implementation.

I don't understand. How can they settle if they are absent? And most of
discussed functions (except C strings and errno) do have portable
implementations in terms of other functions. I see no point in waiting
forever until the thin layer of supplementary convenience wrappers for
array handling is established - it will not appear if we don't make it.

> I think we should use symbolic error codes in Haskell, like the
> `ENOENT' style in C.  This is for portability, because as you may
> know, on different operating systems, symbolic names map to different
> ints. I would hate to see magic numbers like '35' on IRIX but '54' on
> SunOS appearing in code.

First of all, in the case of errno I don't see the need of exposing
particular constans to Haskell programmers. Usually it's enough (and
necessary) to convert errno to Haskell's exception.

There are sometimes cases where specific errno values are needed. The
situation is no different than for other symbolic constants, like F_GETFL.
There is just a need for a more convenient generic solution than wrapping
all these values in functions - which is portable but really painful. It
does not matter if it will be hsc2hs or something different, but it will
be needed anyway, so we don't have to go a hard way for errno.

> data ErrNo = EPERM | ENOENT | ESRCH | EINTR | EIO | ENXIO | E2BIG | ENOEXEC
> 		| EBADF | ECHILD | ....  deriving (Eq,Enum,Show)

I think it's a bad idea. Not only for errno, but for many similar things,
e.g. socket types in module SocketPrim.

It's not extensible. Assume that one standard defines some constants and
another includes the previous one but defines more. Then in your framework
the very first implementation must know all values from all standards,
hide ones that don't belong to the standard it exposes, export them
through a private module and let other modules reexport them for the wide
audience.

It really bites in practice. Linux kernels 2.2.x provide packet sockets.
I cannot use them with ghc's Socket / SocketPrim because the set of
supported enums is hardwired into the implementation!

I propose one of the following methods for such cases. First is to use a
non-abstract type - either a type like CInt which directly corresponds to
these values in C, or a newtype with the exported constructor, or a type
with Num instance. Export values known to be present as plain variables.
Then a programmer which must access a value which was not supported can do
it.

The second way is paranoid: do the same but export the type abstractly.
This is as safe as your solution, but uses the same style of interface
as non-paranoid solutions, and allows exporting the representation through
a private module for those who really need it.

Both solutions are better than algebraic types wrt. efficiency and the
ease of implementation. Efficiency is obvious: values need not to be
remapped each time. And it's very easy to implement it when we have some
generic mechanism for accessing enums and #defines from Haskell, like
hsc2hs. I tried to go the algebraic type way without hsc2hs - it is very
painful and requires a third layer between.

Also there is no problem what to do with error codes we don't understand.
Just pass them unmodified to the user of the module - he must handle some
default anyway.

Since there is currently no way to let the syntax of constructors
represent an abstract datatype ("views"), algebraic types should not be
abused. They are applicable when the set of constants is really decided
once and forever. My interface can be a wrapper for your implementation
but it's harder in the opposite direction.

> For some machines Eq is insufficiently strong, and the following kind
> of patch-up is required:
> 
>     eqErrNo :: ErrNo -> ErrNo -> Bool
>     eqErrNo EWOULDBLOCK EAGAIN = True
>     eqErrNo EAGAIN EWOULDBLOCK = True
>     eqErrNo EDEADLOCK EDEADLK = True
>     eqErrNo EDEADLK EDEADLOCK = True
>     eqErrNo ENOTSUP EOPNOTSUPP = True
>     eqErrNo EOPNOTSUPP ENOTSUP = True
>     eqErrNo a b = a==b

Not needed in my solution. You can export the same constant under several
names.

-- 
Marcin 'Qrczak' Kowalczyk






More information about the FFI mailing list