5.5.2 Creating Foreign Objects

Foreign objects contain zero or more “slots” of data. A slot can hold a pointer, an integer that fits into a size_t or ssize_t, or a SCM value.

All objects of a given foreign type have the same number of slots. In the example from the previous section, the image type has one slot, because the slots list passed to scm_make_foreign_object_type is of length one. (The actual names given to slots are unimportant for most users of the C interface, but can be used on the Scheme side to introspect on the foreign object.)

To construct a foreign object and initialize its first slot, call scm_make_foreign_object_1 (type, first_slot_value). There are similarly named constructors for initializing 0, 1, 2, or 3 slots, or initializing n slots via an array. See Foreign Objects, for full details. Any fields that are not explicitly initialized are set to 0.

To get or set the value of a slot by index, you can use the scm_foreign_object_ref and scm_foreign_object_set_x functions. These functions take and return values as void * pointers; there are corresponding convenience procedures like _signed_ref, _unsigned_set_x and so on for dealing with slots as signed or unsigned integers.

Foreign objects fields that are pointers can be tricky to manage. If possible, it is best that all memory that is referenced by a foreign object be managed by the garbage collector. That way, the GC can automatically ensure that memory is accessible when it is needed, and freed when it becomes inaccessible. If this is not the case for your program – for example, if you are exposing an object to Scheme that was allocated by some other, Guile-unaware part of your program – then you will probably need to implement a finalizer. See Foreign Object Memory Management, for more.

Continuing the example from the previous section, if the global variable image_type contains the type returned by scm_make_foreign_object_type, here is how we could construct a foreign object whose “data” field contains a pointer to a freshly allocated struct image:

SCM
make_image (SCM name, SCM s_width, SCM s_height)
{
  struct image *image;
  int width = scm_to_int (s_width);
  int height = scm_to_int (s_height);

  /* Allocate the `struct image'.  Because we
     use scm_gc_malloc, this memory block will
     be automatically reclaimed when it becomes
     inaccessible, and its members will be traced
     by the garbage collector.  */
  image = (struct image *)
    scm_gc_malloc (sizeof (struct image), "image");

  image->width = width;
  image->height = height;

  /* Allocating the pixels with
     scm_gc_malloc_pointerless means that the
     pixels data is collectable by GC, but
     that GC shouldn't spend time tracing its
     contents for nested pointers because there
     aren't any.  */
  image->pixels =
    scm_gc_malloc_pointerless (width * height, "image pixels");

  image->name = name;
  image->update_func = SCM_BOOL_F;

  /* Now wrap the struct image* in a new foreign
     object, and return that object.  */
  return scm_make_foreign_object_1 (image_type, image);
}

We use scm_gc_malloc_pointerless for the pixel buffer to tell the garbage collector not to scan it for pointers. Calls to scm_gc_malloc, scm_make_foreign_object_1, and scm_gc_malloc_pointerless raise an exception in out-of-memory conditions; the garbage collector is able to reclaim previously allocated memory if that happens.