improve documentation for structs
[bpt/guile.git] / doc / ref / api-compound.texi
index 6fc5b2e..d020774 100644 (file)
@@ -1,7 +1,7 @@
 @c -*-texinfo-*-
 @c This is part of the GNU Guile Reference Manual.
 @c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-@c   2007, 2009, 2010, 2011  Free Software Foundation, Inc.
+@c   2007, 2009, 2010, 2011, 2012  Free Software Foundation, Inc.
 @c See the file guile.texi for copying conditions.
 
 @node Compound Data Types
@@ -2257,6 +2257,10 @@ Return a new list whose contents match those of @var{vlist}.
 A @dfn{record type} is a first class object representing a user-defined
 data type.  A @dfn{record} is an instance of a record type.
 
+Note that in many ways, this interface is too low-level for every-day
+use.  Most uses of records are better served by SRFI-9 records.
+@xref{SRFI-9}.
+
 @deffn {Scheme Procedure} record? obj
 Return @code{#t} if @var{obj} is a record of any type and @code{#f}
 otherwise.
@@ -2355,24 +2359,26 @@ created the type represented by @var{rtd}.
 @tpindex Structures
 
 A @dfn{structure} is a first class data type which holds Scheme values
-or C words in fields numbered 0 upwards.  A @dfn{vtable} represents a
-structure type, giving field types and permissions, and an optional
-print function for @code{write} etc.
+or C words in fields numbered 0 upwards.  A @dfn{vtable} is a structure
+that represents a structure type, giving field types and permissions,
+and an optional print function for @code{write} etc.
 
-Structures are lower level than records (@pxref{Records}) but have
-some extra features.  The vtable system allows sets of types be
-constructed, with class data.  The uninterpreted words can
-inter-operate with C code, allowing arbitrary pointers or other values
-to be stored along side usual Scheme @code{SCM} values.
+Structures are lower level than records (@pxref{Records}).  Usually,
+when you need to represent structured data, you just want to use
+records.  But sometimes you need to implement new kinds of structured
+data abstractions, and for that purpose structures are useful.  Indeed,
+records in Guile are implemented with structures.
 
 @menu
-* Vtables::                     
-* Structure Basics::            
-* Vtable Contents::              
-* Vtable Vtables::              
+* Vtables::
+* Structure Basics::
+* Vtable Contents::
+* Meta-Vtables::
+* Vtable Example::
+* Tail Arrays::
 @end menu
 
-@node Vtables, Structure Basics, Structures, Structures
+@node Vtables
 @subsubsection Vtables
 
 A vtable is a structure type, specifying its layout, and other
@@ -2418,24 +2424,15 @@ The second letter for each field is a permission code,
 @code{o} -- opaque, the field can be neither read nor written at the
 Scheme level.  This can be used for fields which should only be used
 from C code.
-@item
-@code{W},@code{R},@code{O} -- a tail array, with permissions for the
-array fields as per @code{w},@code{r},@code{o}.
 @end itemize
 
-A tail array is further fields at the end of a structure.  The last
-field in the layout string might be for instance @samp{pW} to have a
-tail of writable Scheme-valued fields.  The @samp{pW} field itself
-holds the tail size, and the tail fields come after it.
-
-Here are some examples.
+Here are some examples.  @xref{Tail Arrays}, for information on the
+legacy tail array facility.
 
 @example
 (make-vtable "pw")      ;; one writable field
 (make-vtable "prpw")    ;; one read-only and one writable
 (make-vtable "pwuwuw")  ;; one scheme and two uninterpreted
-
-(make-vtable "prpW")    ;; one fixed then a tail array
 @end example
 
 The optional @var{print} argument is a function called by
@@ -2451,37 +2448,37 @@ structure.
 @example
 (make-vtable "prpw"
              (lambda (struct port)
-               (display "#<" port)
-               (display (struct-ref struct 0) port)
-               (display " and " port)
-               (display (struct-ref struct 1) port)
-               (display ">" port)))
+               (format port "#<~a and ~a>"
+                       (struct-ref struct 0)
+                       (struct-ref struct 1))))
 @end example
 @end deffn
 
 
-@node Structure Basics, Vtable Contents, Vtables, Structures
+@node Structure Basics
 @subsubsection Structure Basics
 
 This section describes the basic procedures for working with
 structures.  @code{make-struct} creates a structure, and
-@code{struct-ref} and @code{struct-set!} access write fields.
+@code{struct-ref} and @code{struct-set!} access its fields.
 
 @deffn {Scheme Procedure} make-struct vtable tail-size init @dots{}
-@deffnx {C Function} scm_make_struct (vtable, tail_size, init_list)
+@deffnx {Scheme Procedure} make-struct/no-tail vtable init @dots{}
 Create a new structure, with layout per the given @var{vtable}
 (@pxref{Vtables}).
 
-@var{tail-size} is the size of the tail array if @var{vtable}
-specifies a tail array.  @var{tail-size} should be 0 when @var{vtable}
-doesn't specify a tail array.
-
 The optional @var{init}@dots{} arguments are initial values for the
-fields of the structure (and the tail array).  This is the only way to
+fields of the structure.  This is the only way to
 put values in read-only fields.  If there are fewer @var{init}
 arguments than fields then the defaults are @code{#f} for a Scheme
 field (type @code{p}) or 0 for an uninterpreted field (type @code{u}).
 
+Structures also have the ability to allocate a variable number of
+additional cells at the end, at their tails.  However, this legacy
+@dfn{tail array} facilty is confusing and inefficient, and so we do not
+recommend it.  @xref{Tail Arrays}, for more on the legacy tail array
+interface.
+
 Type @code{s} self-reference fields, permission @code{o} opaque
 fields, and the count field of a tail array are all ignored for the
 @var{init} arguments, ie.@: an argument is not consumed by such a
@@ -2498,18 +2495,17 @@ For example,
 (struct-ref s 0) @result{} 123
 (struct-ref s 1) @result{} "abc"
 @end example
-
-@example
-(define v (make-vtable "prpW"))
-(define s (make-struct v 6 "fixed field" 'x 'y))
-(struct-ref s 0) @result{} "fixed field"
-(struct-ref s 1) @result{} 2    ;; tail size
-(struct-ref s 2) @result{} x    ;; tail array ...
-(struct-ref s 3) @result{} y
-(struct-ref s 4) @result{} #f
-@end example
 @end deffn
 
+@deftypefn {C Function} SCM scm_make_struct (SCM vtable, SCM tail_size, SCM init_list)
+@deftypefnx {C Function} SCM scm_c_make_struct (SCM vtable, SCM tail_size, SCM init, ...)
+@deftypefnx {C Function} SCM scm_c_make_structv (SCM vtable, SCM tail_size, size_t n_inits, scm_t_bits init[])
+There are a few ways to make structures from C.  @code{scm_make_struct}
+takes a list, @code{scm_c_make_struct} takes variable arguments
+terminated with SCM_UNDEFINED, and @code{scm_c_make_structv} takes a
+packed array.
+@end deftypefn
+
 @deffn {Scheme Procedure} struct? obj
 @deffnx {C Function} scm_struct_p (obj)
 Return @code{#t} if @var{obj} is a structure, or @code{#f} if not.
@@ -2535,36 +2531,34 @@ be written because it's @code{r} read-only or @code{o} opaque.
 
 @deffn {Scheme Procedure} struct-vtable struct
 @deffnx {C Function} scm_struct_vtable (struct)
-Return the vtable used by @var{struct}.
+Return the vtable that describes @var{struct}.
 
-This can be used to examine the layout of an unknown structure, see
-@ref{Vtable Contents}.
+The vtable is effectively the type of the structure.  See @ref{Vtable
+Contents}, for more on vtables.
 @end deffn
 
 
-@node Vtable Contents, Vtable Vtables, Structure Basics, Structures
+@node Vtable Contents
 @subsubsection Vtable Contents
 
-A vtable is itself a structure, with particular fields that hold
-information about the structures to be created.  These include the
-fields of those structures, and the print function for them.  The
-variables below allow access to those fields.
+A vtable is itself a structure.  It has a specific set of fields
+describing various aspects of its @dfn{instances}: the structures
+created from a vtable.  Some of the fields are internal to Guile, some
+of them are part of the public interface, and there may be additional
+fields added on by the user.
 
-@deffn {Scheme Procedure} struct-vtable? obj
-@deffnx {C Function} scm_struct_vtable_p (obj)
-Return @code{#t} if @var{obj} is a vtable structure.
-
-Note that because vtables are simply structures with a particular
-layout, @code{struct-vtable?} can potentially return true on an
-application structure which merely happens to look like a vtable.
-@end deffn
+Every vtable has a field for the layout of their instances, a field for
+the procedure used to print its instances, and a field for the name of
+the vtable itself.  Access to the layout and printer is exposed directly
+via field indexes.  Access to the vtable name is exposed via accessor
+procedures.
 
 @defvr {Scheme Variable} vtable-index-layout
 @defvrx {C Macro} scm_vtable_index_layout
 The field number of the layout specification in a vtable.  The layout
 specification is a symbol like @code{pwpw} formed from the fields
 string passed to @code{make-vtable}, or created by
-@code{make-struct-layout} (@pxref{Vtable Vtables}).
+@code{make-struct-layout} (@pxref{Meta-Vtables}).
 
 @example
 (define v (make-vtable "pwpw" 0))
@@ -2575,12 +2569,6 @@ This field is read-only, since the layout of structures using a vtable
 cannot be changed.
 @end defvr
 
-@defvr {Scheme Variable} vtable-index-vtable
-@defvrx {C Macro} scm_vtable_index_vtable
-A self-reference to the vtable, ie.@: a type @code{s} field.  This is
-used by C code within Guile and has no use at the Scheme level.
-@end defvr
-
 @defvr {Scheme Variable} vtable-index-printer
 @defvrx {C Macro} scm_vtable_index_printer
 The field number of the printer function.  This field contains @code{#f}
@@ -2614,134 +2602,265 @@ from @var{vtable}.
 @end example
 @end deffn
 
-@deffn {Scheme Procedure} struct-vtable-tag vtable
-@deffnx {C Function} scm_struct_vtable_tag (vtable)
-Return the tag of the given @var{vtable}.
-@c
-@c FIXME: what can be said about what this means?
-@c
-@end deffn
 
+@node Meta-Vtables
+@subsubsection Meta-Vtables
 
-@node Vtable Vtables,  , Vtable Contents, Structures
-@subsubsection Vtable Vtables
+As a structure, a vtable also has a vtable, which is also a structure.
+Structures, their vtables, the vtables of the vtables, and so on form a
+tree of structures.  Making a new structure adds a leaf to the tree, and
+if that structure is a vtable, it may be used to create other leaves.
 
-As noted above, a vtable is a structure and that structure is itself
-described by a vtable.  Such a ``vtable of a vtable'' can be created
-with @code{make-vtable-vtable} below.  This can be used to build sets
-of related vtables, possibly with extra application fields.
+If you traverse up the tree of vtables, via calling
+@code{struct-vtable}, eventually you reach a root which is the vtable of
+itself:
 
-This second level of vtable can be a little confusing.  The ball
-example below is a typical use, adding a ``class data'' field to the
-vtables, from which instance structures are created.  The current
-implementation of Guile's own records (@pxref{Records}) does something
-similar, a record type descriptor is a vtable with room to hold the
-field names of the records to be created from it.
+@example
+scheme@@(guile-user)> (current-module)
+$1 = #<directory (guile-user) 221b090>
+scheme@@(guile-user)> (struct-vtable $1)
+$2 = #<record-type module>
+scheme@@(guile-user)> (struct-vtable $2)
+$3 = #<<standard-vtable> 12c30a0>
+scheme@@(guile-user)> (struct-vtable $3)
+$4 = #<<standard-vtable> 12c3fa0>
+scheme@@(guile-user)> (struct-vtable $4)
+$5 = #<<standard-vtable> 12c3fa0>
+scheme@@(guile-user)> <standard-vtable>
+$6 = #<<standard-vtable> 12c3fa0>
+@end example
 
-@deffn {Scheme Procedure} make-vtable-vtable user-fields tail-size [print]
-@deffnx {C Function} scm_make_vtable_vtable (user_fields, tail_size, print_and_init_list)
-Create a ``vtable-vtable'' which can be used to create vtables.  This
-vtable-vtable is also a vtable, and is self-describing, meaning its
-vtable is itself.  The following is a simple usage.
+In this example, we can say that @code{$1} is an instance of @code{$2},
+@code{$2} is an instance of @code{$3}, @code{$3} is an instance of
+@code{$4}, and @code{$4}, strangely enough, is an instance of itself.
+The value bound to @code{$4} in this console session also bound to
+@code{<standard-vtable>} in the default environment.
 
-@example
-(define vt-vt (make-vtable-vtable "" 0))
-(define vt    (make-struct vt-vt 0
-                           (make-struct-layout "pwpw"))
-(define s     (make-struct vt 0 123 456))
+@defvr {Scheme Variable} <standard-vtable>
+A meta-vtable, useful for making new vtables.
+@end defvr
 
-(struct-ref s 0) @result{} 123
-@end example
+All of these values are structures.  All but @code{$1} are vtables.  As
+@code{$2} is an instance of @code{$3}, and @code{$3} is a vtable, we can
+say that @code{$3} is a @dfn{meta-vtable}: a vtable that can create
+vtables.
 
-@code{make-struct} is used to create a vtable from the vtable-vtable.
-The first initializer is a layout object (field
-@code{vtable-index-layout}), usually obtained from
-@code{make-struct-layout} (below).  An optional second initializer is
-a printer function (field @code{vtable-index-printer}), used as
-described under @code{make-vtable} (@pxref{Vtables}).
+With this definition, we can specify more precisely what a vtable is: a
+vtable is a structure made from a meta-vtable.  Making a structure from
+a meta-vtable runs some special checks to ensure that the first field of
+the structure is a valid layout.  Additionally, if these checks see that
+the layout of the child vtable contains all the required fields of a
+vtable, in the correct order, then the child vtable will also be a
+meta-table, inheriting a magical bit from the parent.
 
-@sp 1
-@var{user-fields} is a layout string giving extra fields to have in
-the vtables.  A vtable starts with some base fields as per @ref{Vtable
-Contents}, and @var{user-fields} is appended.  The @var{user-fields}
-start at field number @code{vtable-offset-user} (below), and exist in
-both the vtable-vtable and in the vtables created from it.  Such
-fields provide space for ``class data''.  For example,
+@deffn {Scheme Procedure} struct-vtable? obj
+@deffnx {C Function} scm_struct_vtable_p (obj)
+Return @code{#t} if @var{obj} is a vtable structure: an instance of a
+meta-vtable.
+@end deffn
 
-@example
-(define vt-of-vt (make-vtable-vtable "pw" 0))
-(define vt       (make-struct vt-of-vt 0))
-(struct-set! vt vtable-offset-user "my class data")
-@end example
+@code{<standard-vtable>} is a root of the vtable tree.  (Normally there
+is only one root in a given Guile process, but due to some legacy
+interfaces there may be more than one.)
 
-@var{tail-size} is the size of the tail array in the vtable-vtable
-itself, if @var{user-fields} specifies a tail array.  This should be 0
-if nothing extra is required or the format has no tail array.  The
-tail array field such as @samp{pW} holds the tail array size, as
-usual, and is followed by the extra space.
+The set of required fields of a vtable is the set of fields in the
+@code{<standard-vtable>}, and is bound to @code{standard-vtable-fields}
+in the default environment.  It is possible to create a meta-vtable that
+with additional fields in its layout, which can be used to create
+vtables with additional data:
 
 @example
-(define vt-vt (make-vtable-vtable "pW" 20))
-(define my-vt-tail-start (1+ vtable-offset-user))
-(struct-set! vt-vt (+ 3 my-vt-tail-start) "data in tail")
+scheme@@(guile-user)> (struct-ref $3 vtable-index-layout)
+$6 = pruhsruhpwphuhuhprprpw
+scheme@@(guile-user)> (struct-ref $4 vtable-index-layout)
+$7 = pruhsruhpwphuhuh
+scheme@@(guile-user)> standard-vtable-fields 
+$8 = "pruhsruhpwphuhuh"
+scheme@@(guile-user)> (struct-ref $2 vtable-offset-user)
+$9 = module
 @end example
 
-The optional @var{print} argument is used by @code{display} and
-@code{write} (etc) to print the vtable-vtable and any vtables created
-from it.  It's called as @code{(@var{print} vtable port)} and should
-look at @var{vtable} and write to @var{port}.  The default is the
-usual structure print function, which just gives machine addresses.
-@end deffn
+In this continuation of our earlier example, @code{$2} is a vtable that
+has extra fields, because its vtable, @code{$3}, was made from a
+meta-vtable with an extended layout.  @code{vtable-offset-user} is a
+convenient definition that indicates the number of fields in
+@code{standard-vtable-fields}.
+
+@defvr {Scheme Variable} standard-vtable-fields
+A string containing the orderedq set of fields that a vtable must have.
+@end defvr
+
+@defvr {Scheme Variable} vtable-offset-user
+The first index in a vtable that is available for a user.
+@end defvr
 
 @deffn {Scheme Procedure} make-struct-layout fields
 @deffnx {C Function} scm_make_struct_layout (fields)
 Return a structure layout symbol, from a @var{fields} string.
 @var{fields} is as described under @code{make-vtable}
 (@pxref{Vtables}).  An invalid @var{fields} string is an error.
+@end deffn
+
+With these definitions, one can define @code{make-vtable} in this way:
 
 @example
-(make-struct-layout "prpW") @result{} prpW
-(make-struct-layout "blah") @result{} ERROR
+(define* (make-vtable fields #:optional printer)
+  (make-struct/no-tail <standard-vtable>
+    (make-struct-layout fields)
+    printer))
 @end example
-@end deffn
 
-@defvr {Scheme Variable} vtable-offset-user
-@defvrx {C Macro} scm_vtable_offset_user
-The first field in a vtable which is available for application use.
-Such fields only exist when specified by @var{user-fields} in
-@code{make-vtable-vtable} above.
-@end defvr
 
-@sp 1
-Here's an extended vtable-vtable example, creating classes of
-``balls''.  Each class has a ``colour'', which is fixed.  Instances of
-those classes are created, and such each such ball has an ``owner'',
-which can be changed.
+@node Vtable Example
+@subsubsection Vtable Example
 
-@lisp
-(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 @result{} #<a green ball owned by Nisse>
-@end lisp
+Let us bring these points together with an example.  Consider a simple
+object system with single inheritance.  Objects will be normal
+structures, and classes will be vtables with three extra class fields:
+the name of the class, the parent class, and the list of fields.
+
+So, first we need a meta-vtable that allocates instances with these
+extra class fields.
+
+@example
+(define <class>
+  (make-vtable
+   (string-append standard-vtable-fields "pwpwpw")
+   (lambda (x port)
+     (format port "<<class> ~a>" (class-name x)))))
+
+(define (class? x)
+  (and (struct? x)
+       (eq? (struct-vtable x) <class>)))
+@end example
+
+To make a structure with a specific meta-vtable, we will use
+@code{make-struct/no-tail}, passing it the computed instance layout and
+printer, as with @code{make-vtable}, and additionally the extra three
+class fields.
+
+@example
+(define (make-class name parent fields)
+  (let* ((fields (compute-fields parent fields))
+         (layout (compute-layout fields)))
+    (make-struct/no-tail <class>
+      layout 
+      (lambda (x port)
+        (print-instance x port))
+      name
+      parent
+      fields)))
+@end example
+
+Instances will store their associated data in slots in the structure: as
+many slots as there are fields.  The @code{compute-layout} procedure
+below can compute a layout, and @code{field-index} returns the slot
+corresponding to a field.
+
+@example
+(define-syntax-rule (define-accessor name n)
+  (define (name obj)
+    (struct-ref obj n)))
+
+;; Accessors for classes
+(define-accessor class-name (+ vtable-offset-user 0))
+(define-accessor class-parent (+ vtable-offset-user 1))
+(define-accessor class-fields (+ vtable-offset-user 2))
+
+(define (compute-fields parent fields)
+  (if parent
+      (append (class-fields parent) fields)
+      fields))
+
+(define (compute-layout fields)
+  (make-struct-layout
+   (string-concatenate (make-list (length fields) "pw"))))
+
+(define (field-index class field)
+  (list-index (class-fields class) field))
+
+(define (print-instance x port)
+  (format port "<~a" (class-name (struct-vtable x)))
+  (for-each (lambda (field idx)
+              (format port " ~a: ~a" field (struct-ref x idx)))
+            (class-fields (struct-vtable x))
+            (iota (length (class-fields (struct-vtable x)))))
+  (format port ">"))
+@end example
+
+So, at this point we can actually make a few classes:
+
+@example
+(define-syntax-rule (define-class name parent field ...)
+  (define name (make-class 'name parent '(field ...))))
+
+(define-class <surface> #f
+  width height)
+
+(define-class <window> <surface>
+  x y)
+@end example
+
+And finally, make an instance:
+
+@example
+(make-struct/no-tail <window> 400 300 10 20)
+@result{} <<window> width: 400 height: 300 x: 10 y: 20>
+@end example
+
+And that's that.  Note that there are many possible optimizations and
+feature enhancements that can be made to this object system, and the
+included GOOPS system does make most of them.  For more simple use
+cases, the records facility is usually sufficient.  But sometimes you
+need to make new kinds of data abstractions, and for that purpose,
+structs are here.
+
+@node Tail Arrays
+@subsubsection Tail Arrays
+
+Guile's structures have a facility whereby each instance of a vtable can
+contain a variable-length tail array of values.  The length of the tail
+array is stored in the structure.  This facility was originally intended
+to allow C code to expose raw C structures with word-sized tail arrays
+to Scheme.
+
+However, the tail array facility is confusing and doesn't work very
+well.  It is very rarely used, but it insinuates itself into all
+invocations of @code{make-struct}.  For this reason the clumsily-named
+@code{make-struct/no-tail} procedure can actually be more elegant in
+actual use, because it doesn't have a random @code{0} argument stuck in
+the middle.
+
+Tail arrays also inhibit optimization by allowing instances to affect
+their shapes.  In the absence of tail arrays, all instances of a given
+vtable have the same number and kinds of fields.  This uniformity can be
+exploited by the runtime and the optimizer.  The presence of tail arrays
+make some of these optimizations more difficult.
+
+Finally, the tail array facility is ad-hoc and does not compose with the
+rest of Guile.  If a Guile user wants an array with user-specified
+length, it's best to use a vector.  It is more clear in the code, and
+the standard optimization techniques will do a good job with it.
+
+That said, we should mention some details about the interface.  A vtable
+that has tail array has upper-case permission descriptors: @code{W},
+@code{R} or @code{O}, correspoding to tail arrays of writable,
+read-only, or opaque elements.  A tail array permission descriptor may
+only appear in the last element of a vtable layout.
+
+For exampple, @samp{pW} indicates a tail of writable Scheme-valued
+fields.  The @samp{pW} field itself holds the tail size, and the tail
+fields come after it.
+
+@example
+(define v (make-vtable "prpW")) ;; one fixed then a tail array
+(define s (make-struct v 6 "fixed field" 'x 'y))
+(struct-ref s 0) @result{} "fixed field"
+(struct-ref s 1) @result{} 2    ;; tail size
+(struct-ref s 2) @result{} x    ;; tail array ...
+(struct-ref s 3) @result{} y
+(struct-ref s 4) @result{} #f
+@end example
 
 
 @node Dictionary Types