Next: , Previous: Describing a New Type, Up: Defining New Types (Smobs)


4.4.2 Creating Instances

Normally, smobs can have one immediate word of data. This word stores either a pointer to an additional memory block that holds the real data, or it might hold the data itself when it fits. The word is large enough for a SCM value, a pointer to void, or an integer that fits into a size_t or ssize_t.

You can also create smobs that have two or three immediate words, and when these words suffice to store all data, it is more efficient to use these super-sized smobs instead of using a normal smob plus a memory block. See Double Smobs, for their discussion.

Guile provides functions for managing memory which are often helpful when implementing smobs. See Memory Blocks.

To retrieve the immediate word of a smob, you use the macro SCM_SMOB_DATA. It can be set with SCM_SET_SMOB_DATA. The 16 extra bits can be accessed with SCM_SMOB_FLAGS and SCM_SET_SMOB_FLAGS.

The two macros SCM_SMOB_DATA and SCM_SET_SMOB_DATA treat the immediate word as if it were of type scm_t_bits, which is an unsigned integer type large enough to hold a pointer to void. Thus you can use these macros to store arbitrary pointers in the smob word.

When you want to store a SCM value directly in the immediate word of a smob, you should use the macros SCM_SMOB_OBJECT and SCM_SET_SMOB_OBJECT to access it.

Creating a smob instance can be tricky when it consists of multiple steps that allocate resources and might fail. It is recommended that you go about creating a smob in the following way:

This procedure ensures that the smob is in a valid state as soon as it exists, that all resources that are allocated for the smob are properly associated with it so that they can be properly freed, and that no SCM values that need to be protected are stored in it while the smob does not yet competely exist and thus can not protect them.

Continuing the example from above, if the global variable image_tag contains a tag returned by scm_make_smob_type, here is how we could construct a smob whose immediate word contains a pointer to a freshly allocated struct image:

     SCM
     make_image (SCM name, SCM s_width, SCM s_height)
     {
       SCM smob;
       struct image *image;
       int width = scm_to_int (s_width);
       int height = scm_to_int (s_height);
     
       /* Step 1: Allocate the memory block.
        */
       image = (struct image *) scm_gc_malloc (sizeof (struct image), "image");
     
       /* Step 2: Initialize it with straight code.
        */
       image->width = width;
       image->height = height;
       image->pixels = NULL;
       image->name = SCM_BOOL_F;
       image->update_func = SCM_BOOL_F;
     
       /* Step 3: Create the smob.
        */
       SCM_NEWSMOB (smob, image_tag, image);
     
       /* Step 4: Finish the initialization.
        */
       image->name = name;
       image->pixels = scm_gc_malloc (width * height, "image pixels");
     
       return smob;
     }

Let us look at what might happen when make_image is called.

The conversions of s_width and s_height to ints might fail and signal an error, thus causing a non-local exit. This is not a problem since no resources have been allocated yet that would have to be freed.

The allocation of image in step 1 might fail, but this is likewise no problem.

Step 2 can not exit non-locally. At the end of it, the image struct is in a valid state for the mark_image and free_image functions (see below).

Step 3 can not exit non-locally either. This is guaranteed by Guile. After it, smob contains a valid smob that is properly initialized and protected, and in turn can properly protect the Scheme values in its image struct.

But before the smob is completely created, SCM_NEWSMOB might cause the garbage collector to run. During this garbage collection, the SCM values in the image struct would be invisible to Guile. It only gets to know about them via the mark_image function, but that function can not yet do its job since the smob has not been created yet. Thus, it is important to not store SCM values in the image struct until after the smob has been created.

Step 4, finally, might fail and cause a non-local exit. In that case, the complete creation of the smob has not been successful, but it does nevertheless exist in a valid state. It will eventually be freed by the garbage collector, and all the resources that have been allocated for it will be correctly freed by free_image.