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.