   Guile Reference Manual Copyright (C) 1996 Free Software Foundation
Copyright (C) 1997 Free Software Foundation
Copyright (C) 2000 Free Software Foundation
Copyright (C) 2001 Free Software Foundation
Copyright (C) 2002 Free Software Foundation

   Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.

   Permission is granted to copy and distribute modified versions of
this manual under the conditions for verbatim copying, provided that
the entire resulting derived work is distributed under the terms of a
permission notice identical to this one.

   Permission is granted to copy and distribute translations of this
manual into another language, under the above conditions for modified
versions, except that this permission notice may be stated in a
translation approved by the Free Software Foundation.

Creating Instances
------------------

   Like other non-immediate types, smobs start with a cell whose CAR
contains typing information, and whose `cdr' is free for any use.  For
smobs, the `cdr' stores a pointer to the internal C structure holding
the smob-specific data.  To create an instance of a smob type following
these standards, you should use `SCM_NEWSMOB':

 - Macro: void SCM_NEWSMOB (SCM value, long tag, void *data)
     Make VALUE contain a smob instance of the type with tag TAG and
     smob data DATA.  VALUE must be previously declared as C type `SCM'.

   Since it is often the case (e.g., in smob constructors) that you will
create a smob instance and return it, there is also a slightly
specialized macro for this situation:

 - Macro: fn_returns SCM_RETURN_NEWSMOB (long tab, void *data)
     This macro expands to a block of code that creates a smob instance
     of the type with tag TAG and smob data DATA, and returns that
     `SCM' value.  It should be the last piece of code in a block.

   Guile provides the following functions for managing memory, which are
often helpful when implementing smobs:

 - Function: char * scm_must_malloc (long LEN, char *WHAT)
     Allocate LEN bytes of memory, using `malloc', and return a pointer
     to them.

     If there is not enough memory available, invoke the garbage
     collector, and try once more.  If there is still not enough,
     signal an error, reporting that we could not allocate WHAT.

     This function also helps maintain statistics about the size of the
     heap.

 - Function: char * scm_must_realloc (char *ADDR, long OLEN, long LEN,
          char *WHAT)
     Resize (and possibly relocate) the block of memory at ADDR, to
     have a size of LEN bytes, by calling `realloc'.  Return a pointer
     to the new block.

     If there is not enough memory available, invoke the garbage
     collector, and try once more.  If there is still not enough,
     signal an error, reporting that we could not allocate WHAT.

     The value OLEN should be the old size of the block of memory at
     ADDR; it is only used for keeping statistics on the size of the
     heap.

 - Function: void scm_must_free (char *ADDR)
     Free the block of memory at ADDR, using `free'.  If ADDR is zero,
     signal an error, complaining of an attempt to free something that
     is already free.

     This does no record-keeping; instead, the smob's `free' function
     must take care of that.

     This function isn't usually sufficiently different from the usual
     `free' function to be worth using.

   Continuing the above example, if the global variable `image_tag'
contains a tag returned by `scm_newsmob', here is how we could
construct a smob whose CDR contains a pointer to a freshly allocated
`struct image':

     struct image {
       int width, height;
       char *pixels;

       /* The name of this image */
       SCM name;

       /* A function to call when this image is
          modified, e.g., to update the screen,
          or SCM_BOOL_F if no action necessary */
       SCM update_func;
     };

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

       SCM_ASSERT (SCM_NIMP (name) && SCM_STRINGP (name), name,
                   SCM_ARG1, "make-image");
       SCM_ASSERT (SCM_INUMP (s_width),  s_width,  SCM_ARG2, "make-image");
       SCM_ASSERT (SCM_INUMP (s_height), s_height, SCM_ARG3, "make-image");

       width = SCM_INUM (s_width);
       height = SCM_INUM (s_height);

       image = (struct image *) scm_must_malloc (sizeof (struct image), "image");
       image->width = width;
       image->height = height;
       image->pixels = scm_must_malloc (width * height, "image pixels");
       image->name = name;
       image->update_func = SCM_BOOL_F;

       SCM_RETURN_NEWSMOB (image_tag, image);
     }

Typechecking
------------

   Functions that operate on smobs should aggressively check the types
of their arguments, to avoid misinterpreting some other datatype as a
smob, and perhaps causing a segmentation fault.  Fortunately, this is
pretty simple to do.  The function need only verify that its argument
is a non-immediate, whose CAR is the type tag returned by `scm_newsmob'.

   For example, here is a simple function that operates on an image
smob, and checks the type of its argument.  We also present an expanded
version of the `init_image_type' function, to make `clear_image' and
the image constructor function `make_image' visible to Scheme code.
     SCM
     clear_image (SCM image_smob)
     {
       int area;
       struct image *image;

       SCM_ASSERT ((SCM_NIMP (image_smob)
                    && SCM_CAR (image_smob) == image_tag),
                   image_smob, SCM_ARG1, "clear-image");

       image = (struct image *) SCM_CDR (image_smob);
       area = image->width * image->height;
       memset (image->pixels, 0, area);

       /* Invoke the image's update function.  */
       if (image->update_func != SCM_BOOL_F)
         scm_apply (image->update_func, SCM_EOL, SCM_EOL);

       return SCM_UNSPECIFIED;
     }

     void
     init_image_type ()
     {
       image_tag = scm_newsmob (&image_funs);

       scm_make_gsubr ("make-image", 3, 0, 0, make_image);
       scm_make_gsubr ("clear-image", 1, 0, 0, clear_image);
     }

   Note that checking types is a little more complicated during garbage
collection; see the description of `SCM_GCTYP16' in Garbage Collecting Smobs.

Garbage Collecting Smobs
------------------------

   Once a smob has been released to the tender mercies of the Scheme
system, it must be prepared to survive garbage collection.  Guile calls
the `mark' and `free' functions of the `scm_smobfuns' structure to
manage this.

   As described before (see Garbage Collection), every object in the
Scheme system has a "mark bit", which the garbage collector uses to
tell live objects from dead ones.  When collection starts, every
object's mark bit is clear.  The collector traces pointers through the
heap, starting from objects known to be live, and sets the mark bit on
each object it encounters.  When it can find no more unmarked objects,
the collector walks all objects, live and dead, frees those whose mark
bits are still clear, and clears the mark bit on the others.

   The two main portions of the collection are called the "mark phase",
during which the collector marks live objects, and the "sweep phase",
during which the collector frees all unmarked objects.

   The mark bit of a smob lives in its CAR, along with the smob's type
tag.  When the collector encounters a smob, it sets the smob's mark bit,
and uses the smob's type tag to find the appropriate `mark' function
for that smob: the one listed in that smob's `scm_smobfuns' structure.
It then calls the `mark' function, passing it the smob as its only
argument.

   The `mark' function is responsible for marking any other Scheme
objects the smob refers to.  If it does not do so, the objects' mark
bits will still be clear when the collector begins to sweep, and the
collector will free them.  If this occurs, it will probably break, or at
least confuse, any code operating on the smob; the smob's `SCM' values
will have become dangling references.

   To mark an arbitrary Scheme object, the `mark' function may call
this function:

 - Function: void scm_gc_mark (SCM X)
     Mark the object X, and recurse on any objects X refers to.  If X's
     mark bit is already set, return immediately.

   Thus, here is how we might write the `mark' function for the image
smob type discussed above:
     SCM
     mark_image (SCM image_smob)
     {
       /* Mark the image's name and update function.  */
       struct image *image = (struct image *) SCM_CDR (image_smob);

       scm_gc_mark (image->name);
       scm_gc_mark (image->update_func);

       return SCM_BOOL_F;
     }

   Note that, even though the image's `update_func' could be an
arbitrarily complex structure (representing a procedure and any values
enclosed in its environment), `scm_gc_mark' will recurse as necessary
to mark all its components.  Because `scm_gc_mark' sets an object's
mark bit before it recurses, it is not confused by circular structures.

   As an optimization, the collector will mark whatever value is
returned by the `mark' function; this helps limit depth of recursion
during the mark phase.  Thus, the code above could also be written as:
     SCM
     mark_image (SCM image_smob)
     {
       /* Mark the image's name and update function.  */
       struct image *image = (struct image *) SCM_CDR (image_smob);

       scm_gc_mark (image->name);
       return image->update_func;
     }

   Finally, when the collector encounters an unmarked smob during the
sweep phase, it uses the smob's tag to find the appropriate `free'
function for the smob.  It then calls the function, passing it the smob
as its only argument.

   The `free' function must release any resources used by the smob.
However, it need not free objects managed by the collector; the
collector will take care of them.  The return type of the `free'
function should be `scm_sizet', an unsigned integral type; the `free'
function should return the number of bytes released, to help the
collector maintain statistics on the size of the heap.

   Here is how we might write the `free' function for the image smob
type:
     scm_sizet
     free_image (SCM image_smob)
     {
       struct image *image = (struct image *) SCM_CDR (image_smob);
       scm_sizet size = image->width * image->height + sizeof (*image);

       free (image->pixels);
       free (image);

       return size;
     }

   During the sweep phase, the garbage collector will clear the mark
bits on all live objects.  The code which implements a smob need not do
this itself.

   There is no way for smob code to be notified when collection is
complete.

   Note that, since a smob's mark bit lives in its CAR, along with the
smob's type tag, the technique for checking the type of a smob described
in Typechecking will not necessarily work during GC.  If you
need to find out whether a given object is a particular smob type
during GC, use the following macro:

 - Macro: void SCM_GCTYP16 (SCM X)
     Return the type bits of the smob X, with the mark bit clear.

     Use this macro instead of `SCM_CAR' to check the type of a smob
     during GC.  Usually, only code called by the smob's `mark' function
     need worry about this.

   It is usually a good idea to minimize the amount of processing done
during garbage collection; keep `mark' and `free' functions very
simple.  Since collections occur at unpredictable times, it is easy for
any unusual activity to interfere with normal code.

A Common Mistake In Allocating Smobs
------------------------------------

   When constructing new objects, you must be careful that the garbage
collector can always find any new objects you allocate.  For example,
suppose we wrote the `make_image' function this way:

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

       SCM_ASSERT (SCM_NIMP (name) && SCM_STRINGP (name), name,
                   SCM_ARG1, "make-image");
       SCM_ASSERT (SCM_INUMP (s_width),  s_width,  SCM_ARG2, "make-image");
       SCM_ASSERT (SCM_INUMP (s_height), s_height, SCM_ARG3, "make-image");

       width = SCM_INUM (s_width);
       height = SCM_INUM (s_height);

       image = (struct image *) scm_must_malloc (sizeof (struct image), "image");
       image->width = width;
       image->height = height;
       image->pixels = scm_must_malloc (width * height, "image pixels");

       /* THESE TWO LINES HAVE CHANGED: */
       image->name = scm_string_copy (name);
       image->update_func = scm_make_gsubr (...);

       SCM_NEWCELL (image_smob);
       SCM_SETCDR (image_smob, image);
       SCM_SETCAR (image_smob, image_tag);

       return image_smob;
     }

   This code is incorrect.  The calls to `scm_string_copy' and
`scm_make_gsubr' allocate fresh objects.  Allocating any new object may
cause the garbage collector to run.  If `scm_make_gsubr' invokes a
collection, the garbage collector has no way to discover that
`image->name' points to the new string object; the `image' structure is
not yet part of any Scheme object, so the garbage collector will not
traverse it.  Since the garbage collector cannot find any references to
the new string object, it will free it, leaving `image' pointing to a
dead object.

   A correct implementation might say, instead:
       image->name = SCM_BOOL_F;
       image->update_func = SCM_BOOL_F;

       SCM_NEWCELL (image_smob);
       SCM_SETCDR (image_smob, image);
       SCM_SETCAR (image_smob, image_tag);

       image->name = scm_string_copy (name);
       image->update_func = scm_make_gsubr (...);

       return image_smob;

   Now, by the time we allocate the new string and function objects,
`image_smob' points to `image'.  If the garbage collector scans the
stack, it will find a reference to `image_smob' and traverse `image',
so any objects `image' points to will be preserved.

Garbage Collecting Simple Smobs
-------------------------------

   It is often useful to define very simple smob types -- smobs which
have no data to mark, other than the cell itself, or smobs whose CDR is
simply an ordinary Scheme object, to be marked recursively.  Guile
provides some functions to handle these common cases; you can use these
functions as your smob type's `mark' function, if your smob's structure
is simple enough.

   If the smob refers to no other Scheme objects, then no action is
necessary; the garbage collector has already marked the smob cell
itself.  In that case, you can use zero as your mark function.

 - Function: SCM scm_markcdr (SCM X)
     Mark the references in the smob X, assuming that X's CDR contains
     an ordinary Scheme object, and X refers to no other objects.  This
     function simply returns X's CDR.

 - Function: scm_sizet scm_free0 (SCM X)
     Do nothing; return zero.  This function is appropriate for smobs
     that use either zero or `scm_markcdr' as their marking functions,
     and refer to no heap storage, including memory managed by `malloc',
     other than the smob's header cell.

A Complete Example
------------------

   Here is the complete text of the implementation of the image
datatype, as presented in the sections above.  We also provide a
definition for the smob's `print' function, and make some objects and
functions static, to clarify exactly what the surrounding code is using.

   As mentioned above, you can find this code in the Guile
distribution, in `doc/example-smob'.  That directory includes a
makefile and a suitable `main' function, so you can build a complete
interactive Guile shell, extended with the datatypes described here.)

     /* file "image-type.c" */

     #include <stdlib.h>
     #include <libguile.h>

     static long image_tag;

     struct image {
       int width, height;
       char *pixels;

       /* The name of this image */
       SCM name;

       /* A function to call when this image is
          modified, e.g., to update the screen,
          or SCM_BOOL_F if no action necessary */
       SCM update_func;
     };

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

       SCM_ASSERT (SCM_NIMP (name) && SCM_STRINGP (name), name,
                   SCM_ARG1, "make-image");
       SCM_ASSERT (SCM_INUMP (s_width),  s_width,  SCM_ARG2, "make-image");
       SCM_ASSERT (SCM_INUMP (s_height), s_height, SCM_ARG3, "make-image");

       width = SCM_INUM (s_width);
       height = SCM_INUM (s_height);

       image = (struct image *) scm_must_malloc (sizeof (struct image), "image");
       image->width = width;
       image->height = height;
       image->pixels = scm_must_malloc (width * height, "image pixels");
       image->name = name;
       image->update_func = SCM_BOOL_F;

       SCM_NEWCELL (image_smob);
       SCM_SETCDR (image_smob, image);
       SCM_SETCAR (image_smob, image_tag);

       return image_smob;
     }

     static SCM
     clear_image (SCM image_smob)
     {
       int area;
       struct image *image;

       SCM_ASSERT ((SCM_NIMP (image_smob)
                    && SCM_CAR (image_smob) == image_tag),
                   image_smob, SCM_ARG1, "clear-image");

       image = (struct image *) SCM_CDR (image_smob);
       area = image->width * image->height;
       memset (image->pixels, 0, area);

       /* Invoke the image's update function.  */
       if (image->update_func != SCM_BOOL_F)
         scm_apply (image->update_func, SCM_EOL, SCM_EOL);

       return SCM_UNSPECIFIED;
     }

     static SCM
     mark_image (SCM image_smob)
     {
       struct image *image = (struct image *) SCM_CDR (image_smob);

       scm_gc_mark (image->name);
       return image->update_func;
     }

     static scm_sizet
     free_image (SCM image_smob)
     {
       struct image *image = (struct image *) SCM_CDR (image_smob);
       scm_sizet size = image->width * image->height + sizeof (struct image);

       free (image->pixels);
       free (image);

       return size;
     }

     static int
     print_image (SCM image_smob, SCM port, scm_print_state *pstate)
     {
       struct image *image = (struct image *) SCM_CDR (image_smob);

       scm_puts ("#<image ", port);
       scm_display (image->name, port);
       scm_puts (">", port);

       /* non-zero means success */
       return 1;
     }

     static scm_smobfuns image_funs = {
       mark_image, free_image, print_image, 0
     };

     void
     init_image_type ()
     {
       image_tag = scm_newsmob (&image_funs);

       scm_make_gsubr ("clear-image", 1, 0, 0, clear_image);
       scm_make_gsubr ("make-image", 3, 0, 0, make_image);
     }

   Here is a sample build and interaction with the code from the
`example-smob' directory, on the author's machine:

     zwingli:example-smob$ make CC=gcc
     gcc `guile-config compile`   -c image-type.c -o image-type.o
     gcc `guile-config compile`   -c myguile.c -o myguile.o
     gcc image-type.o myguile.o `guile-config link` -o myguile
     zwingli:example-smob$ ./myguile
     guile> make-image
     #<primitive-procedure make-image>
     guile> (define i (make-image "Whistler's Mother" 100 100))
     guile> i
     #<image Whistler's Mother>
     guile> (clear-image i)
     guile> (clear-image 4)
     ERROR: In procedure clear-image in expression (clear-image 4):
     ERROR: Wrong type argument in position 1: 4
     ABORT: (wrong-type-arg)

     Type "(backtrace)" to get more information.
     guile>

Coming Attractions
******************

   Where is the rest of the manual?

   Good question.  At the time of this writing (2002-05), the rest of
the (very comprehensive) manual is still to be integrated into the
guile-1.4.x distribution.

   In the meantime, you can obtain work-in-progress snapshots of the
manual in info and html formats under directory:

     http://www.glug.org/docbits/guile-doc-out/
     http://www.glug.org/docbits/            (parent has tarballs)

   Keep in mind these snapshots are not necessarily specific to
guile-1.4.x.  As the integration progresses, we expect to mark
version-specific information as such.  (Feel free to suggest to the
guile maintainers which areas need attention.)