On Tue, 28 Nov 2000 malcolm-ffi@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