5.7.1.4 Writing Guile Primitives for Dia

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).