[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
5.7.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?
andchange-fill-pattern
primitives. In other words, a primitive likesquare?
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 itsstruct 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).
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated on April 20, 2013 using texi2html 5.0.