Previous Table of Contents Next


4.4.2. Adding Types to Guile

It is often useful to augment Scheme with data types specific to the application, allowing the interpreted code to refer to resources and data structures used by the application. For example, the window values in SCWM are pointers to SCWM’s internal window structures, wrapped with enough typing information to keep the interpreter consistent. Scheme functions such as full-height can manipulate them, and SCWM primitive functions such as lower-window can easily extract the underlying data structure.

Smobs are Guile’s mechanism for adding new types. (Smob is an abbreviation of small object.) The full procedure for defining new smobs is rather involved, so I only sketch it here. Guile’s manual describes the process fully, and examples abound in Guile-based packages such as SCWM and in the Guile source code itself.

To implement a new smob type, the user must first write a set of C functions that Guile may call to perform certain essential housekeeping tasks on instances of the type:

  All Scheme values are managed by the garbage collector, so the programmer must provide mark and free functions for it to call as necessary. When the garbage collector determines that a smob is alive, it calls the smob’s mark function to discover which other objects the smob refers to and mark them as alive too. If the collector determines that a smob is dead, it calls the smob’s free function to deallocate the smob’s memory and release any other resources to which it may refer.
  To allow the standard Scheme display and write functions to print instances of the new type, the programmer must provide a printing function.
  The programmer may supply a function equal? that can call to compare two instances of a smob type.

For example, here is SCWM’s free_font function, called by the garbage collector to destroy unreferenced font objects:

    size_t
    free_font(SCM obj)
    {
     /* OBJ is the font smob to free. Extract the XFont object and the
        font name, free them, and then free the SCWM font object itself. */
     XFreeFont(dpy, XFONT(obj));
     free(FONTNAME(obj));
     free(FONT(obj));
     return (0);
    }

Given the set of housekeeping functions described here, the programmer must initialize a scm_smobfuns structure to point to them. For example, here is SCWM’s declaration of the scm_smobfuns structure for the font data type:

     static scm_smobfuns font_smobfuns =
     {
      &scm_mark0,
      &free_font,
      &print_font,
      0
     };

Because fonts are relatively simple objects, the font_smobfuns structure cites a standard Guile function, scm_mark0, to mark fonts for the garbage collector. The structure lists the free_font function to be called when a font object dies.

Given the initialized scm_smobfuns structure, the application calls scm_newsmob to register the font smob type with Guile, along with several other new types:

     void
     init_scwm_types(void)
     {
      scm_tc16_scwm_font = scm_newsmob(&font_smobfuns);
      scm_tc16_scwm_color = scm_newsmob(&color_smobfuns);
      scm_tc16_scwm_window = scm_newsmob(&window_smobfuns);
      scm_tc16_scwm_menu = scm_newsmob(&menu_smobfuns);
      …
     }

When the application creates a new instance of a smob type, it must tag the instance with the value returned by scm_newsmob; this allows Guile, given a smob, to find the functions to manage it. For example, here is how SCWM allocates a new font object:

     SCM
     load_font(SCM fname)
     {
      …
      /* Allocate storage for our font structure. */
      font = (scwm_font *)safemalloc(sizeof(*font));
      …
      /* Create a new Scheme object, tagged as a font smob, and pointing to
         the storage we have allocated. Notice that scm_tc16_scwm_font
         is the tag returned by scm_newsmob.  */
      SCM_NEWCELL(answer);
      SCM_SETCAR(answer, scm_tc16_scwm_font);
      SCM_SETCDR(answer, (SCM) font);
 
      /* Initialize our font structure.  */
      XFONT(answer) = xfs;
      FONTNAME(answer) = fn;
      …
      return answer;
   }


Previous Table of Contents Next