DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH
 

(guile.info.gz) Dia Smobs

Info Catalog (guile.info.gz) Dia Steps (guile.info.gz) Extending Dia (guile.info.gz) Dia Primitives
 
 17.1.3 How to Represent Dia Data in Scheme
 ------------------------------------------
 
 For all but the most trivial applications, you will probably want to
 allow some representation of your domain objects to exist on the Scheme
 level.  This is where the idea of SMOBs comes in, and with it issues of
 lifetime management and garbage collection.
 
    To get more concrete about this, let's look again at the example we
 gave earlier of how application users can use Guile to build
 higher-level functions from the primitives that Dia itself provides.
 
      (define (change-squares'-fill-pattern new-pattern)
        (for-each-shape current-page
          (lambda (shape)
            (if (square? shape)
                (change-fill-pattern shape new-pattern)))))
 
    Consider what is stored here in the variable `shape'.  For each
 shape on the current page, the `for-each-shape' primitive calls
 `(lambda (shape) ...)' with an argument representing that shape.
 Question is: how is that argument represented on the Scheme level?  The
 issues are as follows.
 
    * Whatever the representation, it has to be decodable again by the C
      code for the `square?' and `change-fill-pattern' primitives.  In
      other words, a primitive like `square?' has somehow to be able to
      turn the value that it receives back into something that points to
      the underlying C structure describing a shape.
 
    * The representation must also cope with Scheme code holding on to
      the value for later use.  What happens if the Scheme code stores
      `shape' in a global variable, but then that shape is deleted (in a
      way that the Scheme code is not aware of), and later on some other
      Scheme code uses that global variable again in a call to, say,
      `square?'?
 
    * The lifetime and memory allocation of objects that exist _only_ in
      the Scheme world is managed automatically by Guile's garbage
      collector using one simple rule: when there are no remaining
      references to an object, the object is considered dead and so its
      memory is freed.  But for objects that exist in both C and Scheme,
      the picture is more complicated; in the case of Dia, where the
      `shape' argument passes transiently in and out of the Scheme
      world, it would be quite wrong the *delete* the underlying C shape
      just because the Scheme code has finished evaluation.  How do we
      avoid this happening?
 
    One resolution of these issues is for the Scheme-level
 representation of a shape to be a new, Scheme-specific C structure
 wrapped up as a SMOB.  The SMOB is what is passed into and out of
 Scheme code, and the Scheme-specific C structure inside the SMOB points
 to Dia's underlying C structure so that the code for primitives like
 `square?' can get at it.
 
    To cope with an underlying shape being deleted while Scheme code is
 still holding onto a Scheme shape value, the underlying C structure
 should have a new field that points to the Scheme-specific SMOB.  When a
 shape is deleted, the relevant code chains through to the
 Scheme-specific structure and sets its pointer back to the underlying
 structure to NULL.  Thus the SMOB value for the shape continues to
 exist, but any primitive code that tries to use it will detect that the
 underlying shape has been deleted because the underlying structure
 pointer is NULL.
 
    So, to summarize the steps involved in this resolution of the problem
 (and assuming that the underlying C structure for a shape is `struct
 dia_shape'):
 
    * Define a new Scheme-specific structure that _points_ to the
      underlying C structure:
 
           struct dia_guile_shape
           {
             struct dia_shape * c_shape;   /* NULL => deleted */
           }
 
    * Add a field to `struct dia_shape' that points to its `struct
      dia_guile_shape' if it has one --
 
           struct dia_shape
           {
             ...
             struct dia_guile_shape * guile_shape;
           }
 
      -- so that C code can set `guile_shape->c_shape' to NULL when the
      underlying shape is deleted.
 
    * Wrap `struct dia_guile_shape' as a SMOB type.
 
    * Whenever you need to represent a C shape onto the Scheme level,
      create a SMOB instance for it, and pass that.
 
    * In primitive code that receives a shape SMOB instance, check the
      `c_shape' field when decoding it, to find out whether the
      underlying C shape is still there.
 
    As far as memory management is concerned, the SMOB values and their
 Scheme-specific structures are under the control of the garbage
 collector, whereas the underlying C structures are explicitly managed in
 exactly the same way that Dia managed them before we thought of adding
 Guile.
 
    When the garbage collector decides to free a shape SMOB value, it
 calls the "SMOB free" function that was specified when defining the
 shape SMOB type.  To maintain the correctness of the `guile_shape' field
 in the underlying C structure, this function should chain through to the
 underlying C structure (if it still exists) and set its `guile_shape'
 field to NULL.
 
    For full documentation on defining and using SMOB types, see 
 Defining New Types (Smobs).
 
Info Catalog (guile.info.gz) Dia Steps (guile.info.gz) Extending Dia (guile.info.gz) Dia Primitives
automatically generated byinfo2html