Foreign types are designed to represent a correspondence between a Scheme data type that is used to represent an object within the Scheme world and a C data type that represents the data object in the C world. Thus we cannot manipulate true C objects in Scheme, nor can we manipulate Scheme objects in C.
Each foreign type has four aspects that together ensure that the correspondence between the Scheme and C objects is maintained. These aspects are all encoded as procedures that either check for validity or convert between representations. Thus a foreign type is not a declarative type so much as a procedural description of how to pass the type. The underlying foreign procedure call mechanism can pass integers and vector-like Scheme objects, and returns integer values. All other objects must be translated into integers or some other basic type, and must be recovered from integers.
The aspects are:
A predicate that returns
#t if the argument is of an acceptable
Scheme type, otherwise returns
The check procedure is used for type-checking.
A procedure of one argument which returns a Scheme object of one of the basic types. It is used to convert an object into a ‘simpler’ object that will eventually be converted into a C object. The legal simpler objects are integers and strings.
A procedure of one argument that, given an integer, returns a Scheme object of a type satisfying check. Its purpose is to convert the result returned by the foreign procedure into a Scheme value.
Some C procedures modify one or more of their arguments. These arguments are passed by reference, i.e. as a pointer to their address. Since a Scheme object might have a different memory layout and storage conventions, it must be passed by copy-in and copy-out rather than by reference. Revert is a procedure of two parameters, the original object passed and the result of convert on that object. Revert may then inspect the converted object and copy back the changes to the original.
Both forms define a windows type.
The first form defines a type in terms of its aspects as described
The second defines the type as being like another type, except for
certain aspects, which are redefined.
Name is the name of the type.
Model is the name of a type.
Check, convert, return and revert are
procedures or the value
#f means use the default value, which in the second form means
use the definition provided for model.
The defaults are
(lambda (x) #t), i.e. unchecked.
(lambda (x) x), i.e. no translation performed.
(lambda (x) x), i.e. no translation performed.
(lambda (x y) unspecific), i.e. no update performed
unchecked windows type (see below) is defined as:
(define-windows-type unchecked #f #f #f #f)
Windows types are not first class values, so they cannot be
stored in variables or defined using
(define my-type unchecked) error→ Unbound variable (define-similar-windows-type my-type unchecked) ;; the correct way
Scheme characters must be converted to integers. This is accomplished as follows:
(define-windows-type char char? ; check char->integer ; convert integer->char ; convert return value #f ; cannot be passed by reference )
The type which is not checked and undergoes only the basic conversion
from a Scheme integer to a C integer or from a Scheme string to a C
pointer to the first byte of the string.
unchecked values are returned as integers.
Scheme booleans are analogous to C integers
bool have been defined as:
(define-windows-type bool boolean? (lambda (x) (if x 1 0)) (lambda (x) (if (eq? x 0) #f #t)) #f)
Scheme characters are converted into C objects of type
which are indistinguishable from small integers.
Various integer types that are passed without conversion.
A string that is passed as a C pointer of type
char* to the first
character in the string.
A string or
#f. The string is passed as a pointer to characters.
The string is correctly null-terminated.
#f is passed as the null
pointer. This is an example where there is a more complex mapping
between C objects and Scheme objects. C’s
char* type is
represented as one of two Scheme types depending on its value. This
allows us us to distinguish between the C string (pointer) that points
to the empty sequence of characters and the null pointer (which doesnt
Various kinds of Win32 handle. These names correspond to the same, but
all uppercase, names in the Windows C language header files. Win32 API
calls are the source of values of this type and the values are
meaningless except as arguments to other Win32 API calls. Currently
these values are represented as integers but we expect that Win32
handles will in future be represented by allocated Scheme objects
(e.g. records) that will allow predicates (e.g.
sensible interlocking with the garbage collector to free the programmer
of the current tedious allocation and deallocation of handles.
A Windows resource identifier is either a small integer or a string. In C, this distinction is possible because pointers look like larger integers, so a machine word representing a small integer can be distinguished from a machine word that is a pointer to the text of the name of the resource.