Once the details of object representation are decided, writing the primitive function code that you need is usually straightforward.
A primitive is simply a C function whose arguments and return value are
all of type SCM
, and whose body does whatever you want it to do.
As an example, here is a possible implementation of the square?
primitive:
static SCM square_p (SCM shape) { struct dia_guile_shape * guile_shape; /* Check that arg is really a shape object. */ scm_assert_foreign_object_type (shape_type, shape); /* Access Scheme-specific shape structure. */ guile_shape = scm_foreign_object_ref (shape, 0); /* Find out if underlying shape exists and is a square; return answer as a Scheme boolean. */ return scm_from_bool (guile_shape->c_shape && (guile_shape->c_shape->type == DIA_SQUARE)); }
Notice how easy it is to chain through from the SCM shape
parameter that square_p
receives — which is a foreign object
— to the Scheme-specific structure inside the foreign object, and
thence to the underlying C structure for the shape.
In this code, scm_assert_foreign_object_type
,
scm_foreign_object_ref
, and scm_from_bool
are from the
standard Guile API. We assume that shape_type
was given to us
when we made the shape foreign object type, using
scm_make_foreign_object_type
. The call to
scm_assert_foreign_object_type
ensures that shape is indeed
a shape. This is needed to guard against Scheme code using the
square?
procedure incorrectly, as in (square? "hello")
;
Scheme’s latent typing means that usage errors like this must be caught
at run time.
Having written the C code for your primitives, you need to make them
available as Scheme procedures by calling the scm_c_define_gsubr
function. scm_c_define_gsubr
(see Primitive Procedures)
takes arguments that specify the Scheme-level name for the primitive and
how many required, optional and rest arguments it can accept. The
square?
primitive always requires exactly one argument, so the
call to make it available in Scheme reads like this:
scm_c_define_gsubr ("square?", 1, 0, 0, square_p);
For where to put this call, see the subsection after next on the structure of Guile-enabled code (see Top-level Structure of Guile-enabled Dia).