4 Specification of External Entities

Each foreign declaration has to specify the external entity that is accessed or provided by that
declaration. The syntax and semantics of the notation that is required to uniquely determine an external
entity depends heavily on the calling convention by which this entity is accessed. For example, for the
calling convention ccall, a global label is sufficient. However, to uniquely identify a method in the
calling convention jvm, type information has to be provided. For the latter, there is a choice
between the Java source-level syntax of types and the syntax expected by JNI--but, clearly, the
syntax of the specification of an external entity depends on the calling convention and may be
non-trivial.

Consequently, the FFI does not fix a general syntax for denoting external entities, but requires both
impent and expent to take the form of a Haskell string literal. The formation rules for the
values of these strings depend on the calling convention and a Haskell system implementing a
particular calling convention will have to parse these strings in accordance with the calling
convention.

Defining impent and expent to take the form of a string implies that all information that is needed to
statically analyse the Haskell program is separated from the information needed to generate the code
interacting with the foreign language. This is, in particular, helpful for tools processing Haskell source
code. When ignoring the entity information provided by impent or expent, foreign import and export
declarations are still sufficient to infer identifier definition and use information as well as type
information.

For more complex calling conventions, there is a choice between the user-level syntax for identifying
entities (e.g., Java or C++) and the system-level syntax (e.g., the type syntax of JNI or mangled C++,
respectively). If such a choice exists, the user-level syntax is preferred. Not only because it is more user
friendly, but also because the system-level syntax may not be entirely independent of the particular
implementation of the foreign language.

The following defines the syntax for specifying external entities and their semantics for the calling
conventions ccall and stdcall. Other calling conventions from Table 1 are expected to be defined in
future versions of this report.

4.1 Standard C Calls

The following defines the structure of external entities for foreign declarations under the ccall calling
convention for both import and export declarations separately. Afterwards additional constraints on the
type of foreign functions are defined.

The FFI covers only access to C functions and global variables. There are no mechanisms to access
other entities of C programs. In particular, there is no support for accessing pre-processor symbols from
Haskell, which includes #defined constants. Access from Haskell to such entities is the domain of
language-specific tools, which provide added convenience over the plain FFI as defined in this
report.

4.1.1 Import Declarations

For import declarations, the syntax for the specification of external entities under the ccall calling
convention is as follows:

impent

" [static] [chname] [&] [cid] "

(static function or address)

|

" dynamic "

(stub factory importing addresses)

|

" wrapper "

(stub factory exporting thunks)

The first alternative either imports a static function cid or, if & precedes the identifier, a static address. If
cid is omitted, it defaults to the name of the imported Haskell variable. The optional filename chname
specifies a C header file, where the intended meaning is that the header file declares the C entity
identified by cid. In particular, when the Haskell system compiles Haskell to C code, the
directive

#include "chname"

needs to be placed into any generated C file that refers to the foreign entity before the first occurrence of
that entity in the generated C file.

The second and third alternative, identified by the keywords dynamic and wrapper, respectively,
import stub functions that have to be generated by the Haskell system. In the case of dynamic, the stub
converts C function pointers into Haskell functions; and conversely, in the case of wrapper, the stub
converts Haskell thunks to C function pointers. If neither of the specifiers static, dynamic, or wrapper
is given, static is assumed. The specifier static is nevertheless needed to import C routines that are
named dynamic or wrapper.

It should be noted that a static foreign declaration that does not import an address (i.e., where & is
not used in the specification of the external entity) always refers to a C function, even if the Haskell type
is non-functional. For example,

foreign import ccall foo :: CInt

refers to a pure C function foo with no arguments that returns an integer value. Similarly, if the type is IOCInt, the declaration refers to an impure nullary function. If a Haskell program needs to access a C
variable bar of integer type,

foreign import ccall "&" bar :: Ptr CInt

must be used to obtain a pointer referring to the variable. The variable can be read and updated using the
routines provided by the module Storable (cf. Section 5.7).

4.1.2 Export Declarations

External entities in ccall export declarations are of the form

expent

" [cid] "

The optional C identifier cid defines the external name by which the exported Haskell variable is
accessible in C. If it is omitted, the external name defaults to the name of the exported Haskell
variable.

4.1.3 Constraints on Foreign Function Types

In the case of import declaration, there are, depending on the kind of import declaration, constraints
regarding the admissible Haskell type that the variable defined in the import may have. These
constraints are specified in the following.

Static Functions.

A static function can be of any foreign type; in particular, the result type
may or may not be in the IO monad. If a function that is not pure is not imported in the
IO monad, the system behaviour is undefined. Generally, no check for consistency with the
C type of the imported label is performed.

As an example, consider

foreign import ccall "static stdlib.h" system :: Ptr CChar -> IO CInt

This declaration imports the system() function whose prototype is available from
stdlib.h.

Static addresses.

The type of an imported address is constrained to be of the form Ptr a or FunPtra, where a can be any type.

As an example, consider

foreign import ccall "errno.h &errno" errno :: Ptr CInt

It imports the address of the variable errno, which is of the C type int.

Dynamic import.

The type of a dynamic stub has to be of the form (FunPtr ft) -> ft, where ft may
be any foreign type.

The stub factory mkCallback turns any Haskell computation of type IO () into a C function
pointer that can be passed to C routines, which can call back into the Haskell context by invoking
the referenced function.

4.1.4 Specification of Header Files

A C header specified in an import declaration is always included by #include "chname". There is no
explicit support for #include <chname> style inclusion. The ISO C99 [3] standard guarantees that any
search path that would be used for a #include <chname> is also used for #include "chname" and it is
guaranteed that these paths are searched after all paths that are unique to #include "chname".
Furthermore, we require that chname ends on .h to make parsing of the specification of external entities
unambiguous.

The specification of include files has been kept to a minimum on purpose. Libraries often require a
multitude of include directives, some of which may be system-dependent. Any design that attempts to
cover all possible configurations would introduce significant complexity. Moreover, in the current design,
a custom include file can be specified that uses the standard C preprocessor features to include all
relevant headers.

Header files have no impact on the semantics of a foreign call, and whether an implementation uses
the header file or not is implementation-defined. However, as some implementations may require a header
file that supplies a correct prototype for external functions in order to generate correct code, portable
FFI code must include suitable header files.

4.1.5 C Argument Promotion

The argument passing conventions of C are dependant on whether a function prototype for the called
functions is in scope at a call site. In particular, if no function prototype is in scope, default argumentpromotion is applied to integral and floating types. In general, it cannot be expected from a Haskell
system that it is aware of whether a given C function was compiled with or without a function prototype
being in scope. For the sake of portability, we thus require that a Haskell system generally implements
calls to C functions as well as C stubs for Haskell functions as if a function prototype for the called
function is in scope.

This convention implies that the onus for ensuring the match between C and Haskell code is placed
on the FFI user. In particular, when a C function that was compiled without a prototype is called from
Haskell, the Haskell signature at the corresponding foreign import declaration must use the types after
argument promotion. For example, consider the following C function definition, which lacks a
prototype:

void foo (a)
float a;
{
...
}

The lack of a prototype implies that a C compiler will apply default argument promotion to the parameter
a, and thus, foo will expect to receive a value of type double, not float. Hence, the correct foreignimport declaration is

foreign import ccall foo :: Double -> IO ()

In contrast, a C function compiled with the prototype

void foo (float a);

requires

foreign import ccall foo :: Float -> IO ()

A similar situation arises in the case of foreign export declarations that use types that would be
altered under the C default argument promotion rules. When calling such Haskell functions from C, a
function prototype matching the signature provided in the foreign export declaration must be in
scope; otherwise, the C compiler will erroneously apply the promotion rules to all function
arguments.

Note that for a C function defined to a accept a variable number of arguments, all arguments beyond
the explicitly typed arguments suffer argument promotion. However, because C permits the
calling convention to be different for such functions; a Haskell system will, in general, not be
able to make use of variable argument functions. Hence, their use is deprecated in portable
code.

4.2 Win32 API Calls

The specification of external entities under the stdcall calling convention is identical to that for
standard C calls. The two calling conventions only differ in the generated code.