The time has come for another "final" :-} word on the low-level API for
Haskell's foreign function interface. It is nothing very deep and most of
it already exists in one form or the other, but I'd like to have some
feedback before I start hacking this into GHC. Additions are proposed in 3
areas:

   1) Mapping Haskell types to C types
   2) Mapping C types to Haskell types
   3) Byte order

1. Mapping Haskell types to C types
===========================================================================
Writing C code which gets called via Haskell's FFI is complicated by the
fact that one needs to know the C types corresponding to Haskell's
types. To solve this problem, every Haskell implementation should come with
a header file FFI.h, which describes this mapping and the corresponding
limits. This is necessary because there is no guarantee that the
implementation uses e.g. int for an Int32, or float for a Float. The
following table is based on section 2.4.3 (Type mapping) of the document "A
primitive foreign function interface".

Haskell type |    C type    | ... is probably |          Range
-------------+--------------+-----------------+---------------------------
Char         |  HsChar      | char (1)        | HsCharMin  .. HsCharMax   
Int          |  HsInt       | int             | HsIntMin   .. HsIntMax    
Int8         |  HsInt8      | signed char     | HsInt8Min  .. HsInt8Max   
Int16        |  HsInt16     | short           | HsInt16Min .. HsInt16Max  
Int32        |  HsInt32     | int             | HsInt32Min .. HsInt32Max  
Int64        |  HsInt64     | long            | HsInt64Min .. HsInt64Max  
Word8        |  HsWord8     | unsigned char   | 0          .. HsWord8Max  
Word16       |  HsWord16    | unsigned short  | 0          .. HsWord16Max 
Word32       |  HsWord32    | unsigned int    | 0          .. HsWord32Max 
Word64       |  HsWord64    | unsigned long   | 0          .. HsWord64Max 
Float        |  HsFloat     | float           | (2)
Double       |  HsDouble    | double          |
Addr         |  HsAddr      | void *          |
StablePtr    |  HsStablePtr | void * (3)      |

Remarks:
========
1) Although the Haskell 98 report states that Char should be a Unicode
   character, a plain char is used here. No implementation uses Unicode so
   far, and char is what one wants most of the time, anyway.

2) Float limits are a little bit more complicated, see ANSI C's float.h:

      Hs{Float,Double}Radix
      Hs{Float,Double}Rounds
      Hs{Float,Double}Epsilon
      Hs{Float,Double}Dig
      Hs{Float,Double}MantDig
      Hs{Float,Double}Min
      Hs{Float,Double}MinExp
      Hs{Float,Double}Min10Exp
      Hs{Float,Double}Max
      Hs{Float,Double}MaxExp
      Hs{Float,Double}Max10Exp

3) Stable pointers are passed as addresses by the FFI, but this is only
   because a void* is used as a generic container in most APIs, not because
   they are real addresses. To make this special case clear, a separate C
   type is used here. Foreign objects are a different matter: They are
   passed as real addresses, so HsAddr is appropriate for them.

2. Mapping C types to Haskell types
===========================================================================
Another problem is finding the right Haskell type for a given C type,
e.g. when using foreign import or foreign export dynamic. To accomplish
this, the module FFI exports the following type synonyms:
(type synonyms)

Haskell type |   C type
-------------+---------------
CChar        | char
CSChar       | signed char
CUChar       | unsigned char
CShort       | short
CInt         | int
CLong        | long
CUShort      | unsigned short
CUInt        | unsigned int
CULong       | unsigned long
CFloat       | float
CDouble      | double

Remarks:
========
1) Manuel Chakravarty's C2HSConfig uses slightly different names, but the
   ones above are more similar to the names used in some common C headers.

2) ANSI C defines long double and some compilers have long longs, but these
   special types are probably not worth the portability trouble.

3) Addr can be used for all kinds of C pointers. Although in theory the
   length of a pointer could depend on the type of data pointed to, this is
   hardly a problem in practice.

4) The following standard types are so ubiquitous that they should probably
   be included, too:   (any further types wanted?)

Haskell type |   C type
-------------+---------------
CSize        | size_t
CSSize       | ssize_t
COff         | off_t
CPtrdiff     | ptrdiff_t

3. Byte order
===========================================================================
For the really dirty stuff one needs to know the byte order of the
underlying architecture:

   data ByteOrder = SmallEndian | BigEndian -- are there more esoteric ones?
   byteOrder :: ByteOrder


Comments/suggestions/flames?

Cheers,
   Sven
-- 
Sven Panne                                        Tel.: +49/89/2178-2235
LMU, Institut fuer Informatik                     FAX : +49/89/2178-2211
LFE Programmier- und Modellierungssprachen              Oettingenstr. 67
mailto:[EMAIL PROTECTED]            D-80538 Muenchen
http://www.informatik.uni-muenchen.de/~Sven.Panne

Reply via email to