Node:Vtables, Previous:Structure Basics, Up:Structures



22.5.4 Vtables

Vtables are structures that are used to represent structure types. Each vtable contains a layout specification in field vtable-index-layout - instances of the type are laid out according to that specification. Vtables contain additional fields which are used only internally to libguile. The variable vtable-offset-user is bound to a field number. Vtable fields at that position or greater are user definable.

struct-vtable handle Scheme Procedure
scm_struct_vtable (handle) C Function
Return the vtable structure that describes the type of struct.

struct-vtable? x Scheme Procedure
scm_struct_vtable_p (x) C Function
Return #t iff x is a vtable structure.

If you have a vtable structure, V, you can create an instance of the type it describes by using (make-struct V ...). But where does V itself come from? One possibility is that V is an instance of a user-defined vtable type, V', so that V is created by using (make-struct V' ...). Another possibility is that V is an instance of the type it itself describes. Vtable structures of the second sort are created by this procedure:

make-vtable-vtable user_fields tail_array_size . init Scheme Procedure
scm_make_vtable_vtable (user_fields, tail_array_size, init) C Function
Return a new, self-describing vtable structure.

user-fields is a string describing user defined fields of the vtable beginning at index vtable-offset-user (see make-struct-layout).

tail-size specifies the size of the tail-array (if any) of this vtable.

init1, ... are the optional initializers for the fields of the vtable.

Vtables have one initializable system field--the struct printer. This field comes before the user fields in the initializers passed to make-vtable-vtable and make-struct, and thus works as a third optional argument to make-vtable-vtable and a fourth to make-struct when creating vtables:

If the value is a procedure, it will be called instead of the standard printer whenever a struct described by this vtable is printed. The procedure will be called with arguments STRUCT and PORT.

The structure of a struct is described by a vtable, so the vtable is in essence the type of the struct. The vtable is itself a struct with a vtable. This could go on forever if it weren't for the vtable-vtables which are self-describing vtables, and thus terminate the chain.

There are several potential ways of using structs, but the standard one is to use three kinds of structs, together building up a type sub-system: one vtable-vtable working as the root and one or several "types", each with a set of "instances". (The vtable-vtable should be compared to the class <class> which is the class of itself.)

(define ball-root (make-vtable-vtable "pr" 0))

(define (make-ball-type ball-color)
  (make-struct ball-root 0
	       (make-struct-layout "pw")
               (lambda (ball port)
                 (format port "#<a ~A ball owned by ~A>"
                         (color ball)
                         (owner ball)))
               ball-color))
(define (color ball) (struct-ref (struct-vtable ball) vtable-offset-user))
(define (owner ball) (struct-ref ball 0))

(define red (make-ball-type 'red))
(define green (make-ball-type 'green))

(define (make-ball type owner) (make-struct type 0 owner))

(define ball (make-ball green 'Nisse))
ball => #<a green ball owned by Nisse>

struct-vtable-name vtable Scheme Procedure
scm_struct_vtable_name (vtable) C Function
Return the name of the vtable vtable.

set-struct-vtable-name! vtable name Scheme Procedure
scm_set_struct_vtable_name_x (vtable, name) C Function
Set the name of the vtable vtable to name.

struct-vtable-tag handle Scheme Procedure
scm_struct_vtable_tag (handle) C Function
Return the vtable tag of the structure handle.