guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] GNU Guile branch, stable-2.0, updated. v2.0.6-7-g880e114


From: Andy Wingo
Subject: [Guile-commits] GNU Guile branch, stable-2.0, updated. v2.0.6-7-g880e114
Date: Sat, 28 Jul 2012 11:19:34 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Guile".

http://git.savannah.gnu.org/cgit/guile.git/commit/?id=880e114b9d06bb488b27a3af1d1fdefcc1f464bd

The branch, stable-2.0 has been updated
       via  880e114b9d06bb488b27a3af1d1fdefcc1f464bd (commit)
       via  07e6d2d4511ed2fe812f0ed4c31f104c85bf8e05 (commit)
       via  6d46f1e48a76e3e5c9066a6e9ed417ac253d9d87 (commit)
       via  41a9e8829c1720da01f3bd471552688806478a51 (commit)
       via  febc7d2f071fcbfafdc976170bd223dd6f2ead38 (commit)
      from  10a97755d4a1b2034f8a131215a92c0b29000969 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 880e114b9d06bb488b27a3af1d1fdefcc1f464bd
Author: Andy Wingo <address@hidden>
Date:   Sat Jul 28 12:28:21 2012 +0200

    set struct names for <standard-vtable>, etc
    
    * libguile/struct.c (scm_init_struct): Set the struct names for
      <standard-vtable>, <applicable-struct-vtable>, and
      <applicable-struct-with-setter-vtable>.

commit 07e6d2d4511ed2fe812f0ed4c31f104c85bf8e05
Author: Andy Wingo <address@hidden>
Date:   Sat Jul 28 12:58:46 2012 +0200

    update tests after vtable-vtable deprecation
    
    * test-suite/tests/goops.test ("classes for built-in types"): Use a
      vtable instead of a vtable-vtable.
    
    * test-suite/tests/structs.test (ball-root)
      ("low-level struct procedures", "make-struct"): Rework to use normal
      vtables instead of making new vtable-vtable.

commit 6d46f1e48a76e3e5c9066a6e9ed417ac253d9d87
Author: Andy Wingo <address@hidden>
Date:   Fri Nov 18 11:50:50 2011 +0100

    deprecate make-vtable-vtable
    
    * libguile/struct.h:
    * libguile/struct.c (scm_make_vtable_vtable): Deprecate, as you can
      handle most of the use cases with make-vtable, and we don't want to
      promote the creation of new roots to the type hierarchy.
      (scm_i_make_vtable_vtable): The internal replacement.

commit 41a9e8829c1720da01f3bd471552688806478a51
Author: Andy Wingo <address@hidden>
Date:   Sat Jul 28 12:43:46 2012 +0200

    improve documentation for structs
    
    * doc/ref/api-compound.texi (Structures): Update to describe
      <standard-vtable>, to remove documentation for make-vtable-vtable, to
      describe meta-vtables, and to add a long example.

commit febc7d2f071fcbfafdc976170bd223dd6f2ead38
Author: Andy Wingo <address@hidden>
Date:   Tue Jul 24 23:18:33 2012 +0200

    update structure documentation
    
    * doc/ref/api-compound.texi (Records): Add a link to SRFI-9 records.
      (Structures): Add a link to Records.  Describe tail arrays as
      deprecated, and add a rationale and some details.

-----------------------------------------------------------------------

Summary of changes:
 doc/ref/api-compound.texi     |  449 ++++++++++++++++++++++++++---------------
 libguile/goops.c              |    2 +-
 libguile/struct.c             |  104 +++++-----
 libguile/struct.h             |    5 +-
 test-suite/tests/goops.test   |    6 +-
 test-suite/tests/structs.test |   12 +-
 6 files changed, 356 insertions(+), 222 deletions(-)

diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
index 78d6789..d020774 100644
--- a/doc/ref/api-compound.texi
+++ b/doc/ref/api-compound.texi
@@ -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.
address@hidden
+
 @deffn {Scheme Procedure} record? obj
 Return @code{#t} if @var{obj} is a record of any type and @code{#f}
 otherwise.
@@ -2355,21 +2359,23 @@ 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
@@ -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.
address@hidden
address@hidden,@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,11 +2448,9 @@ 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
 
@@ -2465,23 +2460,25 @@ structure.
 
 This section describes the basic procedures for working with
 structures.  @code{make-struct} creates a structure, and
address@hidden and @code{struct-set!} access write fields.
address@hidden and @code{struct-set!} access its fields.
 
 @deffn {Scheme Procedure} make-struct vtable tail-size init @dots{}
address@hidden {C Function} scm_make_struct (vtable, tail_size, init_list)
address@hidden {Scheme Procedure} make-struct/no-tail vtable init @dots{}
 Create a new structure, with layout per the given @var{vtable}
 (@pxref{Vtables}).
 
address@hidden 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 @address@hidden 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
address@hidden 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
-
address@hidden
-(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
address@hidden example
 @end deffn
 
address@hidden {C Function} SCM scm_make_struct (SCM vtable, SCM tail_size, SCM 
init_list)
address@hidden {C Function} SCM scm_c_make_struct (SCM vtable, SCM tail_size, 
SCM init, ...)
address@hidden {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.
address@hidden 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
address@hidden Contents}.
+The vtable is effectively the type of the structure.  See @ref{Vtable
+Contents}, for more on vtables.
 @end deffn
 
 
 @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.
 
address@hidden {Scheme Procedure} struct-vtable? obj
address@hidden {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.
address@hidden 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
address@hidden (@pxref{Vtable Vtables}).
address@hidden (@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
 
address@hidden {Scheme Variable} vtable-index-vtable
address@hidden {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.
address@hidden 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}
@@ -2615,125 +2603,264 @@ from @var{vtable}.
 @end deffn
 
 
address@hidden Vtable Vtables
address@hidden Vtable Vtables
address@hidden Meta-Vtables
address@hidden Meta-Vtables
 
-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.
+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.
 
-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.
-
address@hidden {Scheme Procedure} make-vtable-vtable user-fields tail-size 
[print]
address@hidden {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.
+If you traverse up the tree of vtables, via calling
address@hidden, eventually you reach a root which is the vtable of
+itself:
 
 @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))
-
-(struct-ref s 0) @result{} 123
+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
 
address@hidden is used to create a vtable from the vtable-vtable.
-The first initializer is a layout object (field
address@hidden), usually obtained from
address@hidden (below).  An optional second initializer is
-a printer function (field @code{vtable-index-printer}), used as
-described under @code{make-vtable} (@pxref{Vtables}).
+In this example, we can say that @code{$1} is an instance of @code{$2},
address@hidden is an instance of @code{$3}, @code{$3} is an instance of
address@hidden, and @code{$4}, strangely enough, is an instance of itself.
+The value bound to @code{$4} in this console session also bound to
address@hidden<standard-vtable>} in the default environment.
 
address@hidden 1
address@hidden 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,
address@hidden {Scheme Variable} <standard-vtable>
+A meta-vtable, useful for making new vtables.
address@hidden defvr
 
address@hidden
-(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")
address@hidden example
+All of these values are structures.  All but @code{$1} are vtables.  As
address@hidden 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.
 
address@hidden 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.
+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.
+
address@hidden {Scheme Procedure} struct-vtable? obj
address@hidden {C Function} scm_struct_vtable_p (obj)
+Return @code{#t} if @var{obj} is a vtable structure: an instance of a
+meta-vtable.
address@hidden deffn
+
address@hidden<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.)
+
+The set of required fields of a vtable is the set of fields in the
address@hidden<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
address@hidden (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.
address@hidden 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
address@hidden
+
address@hidden {Scheme Variable} standard-vtable-fields
+A string containing the orderedq set of fields that a vtable must have.
address@hidden defvr
+
address@hidden {Scheme Variable} vtable-offset-user
+The first index in a vtable that is available for a user.
address@hidden 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.
address@hidden 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
address@hidden deffn
 
address@hidden {Scheme Variable} vtable-offset-user
address@hidden {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
address@hidden above.
address@hidden defvr
 
address@hidden 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.
address@hidden Vtable Example
address@hidden Vtable Example
 
address@hidden
-(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>
address@hidden 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.
+
address@hidden
+(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>)))
address@hidden example
+
+To make a structure with a specific meta-vtable, we will use
address@hidden/no-tail}, passing it the computed instance layout and
+printer, as with @code{make-vtable}, and additionally the extra three
+class fields.
+
address@hidden
+(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)))
address@hidden 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.
+
address@hidden
+(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 ">"))
address@hidden example
+
+So, at this point we can actually make a few classes:
+
address@hidden
+(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)
address@hidden example
+
+And finally, make an instance:
+
address@hidden
+(make-struct/no-tail <window> 400 300 10 20)
address@hidden <<window> width: 400 height: 300 x: 10 y: 20>
address@hidden 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.
+
address@hidden Tail Arrays
address@hidden 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
address@hidden/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},
address@hidden 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.
+
address@hidden
+(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
address@hidden example
 
 
 @node Dictionary Types
diff --git a/libguile/goops.c b/libguile/goops.c
index f4b2b34..9a40277 100644
--- a/libguile/goops.c
+++ b/libguile/goops.c
@@ -982,7 +982,7 @@ create_basic_classes (void)
   /**** <class> ****/
   SCM cs = scm_from_locale_string (SCM_CLASS_CLASS_LAYOUT);
   SCM name = scm_from_latin1_symbol ("<class>");
-  scm_class_class = scm_make_vtable_vtable (cs, SCM_INUM0, SCM_EOL);
+  scm_class_class = scm_i_make_vtable_vtable (cs);
   SCM_SET_CLASS_FLAGS (scm_class_class, (SCM_CLASSF_GOOPS_OR_VALID
                                         | SCM_CLASSF_METACLASS));
 
diff --git a/libguile/struct.c b/libguile/struct.c
index a5c4e3a..5837b7c 100644
--- a/libguile/struct.c
+++ b/libguile/struct.c
@@ -24,6 +24,8 @@
 #include <alloca.h>
 #include <assert.h>
 
+#define SCM_BUILDING_DEPRECATED_CODE
+
 #include "libguile/_scm.h"
 #include "libguile/async.h"
 #include "libguile/chars.h"
@@ -562,53 +564,10 @@ SCM_DEFINE (scm_make_struct, "make-struct", 2, 0, 1,
 
 
 
-SCM_DEFINE (scm_make_vtable_vtable, "make-vtable-vtable", 2, 0, 1,
-            (SCM user_fields, SCM tail_array_size, SCM init),
-           "Return a new, self-describing vtable structure.\n\n"
-           "@var{user-fields} is a string describing user defined fields of 
the\n"
-           "vtable beginning at index @code{vtable-offset-user}\n"
-           "(see @code{make-struct-layout}).\n\n"
-           "@var{tail_array_size} specifies the size of the tail-array (if 
any) of\n"
-           "this vtable.\n\n"
-           "@var{init1}, @dots{} are the optional initializers for the fields 
of\n"
-           "the vtable.\n\n"
-           "Vtables have one initializable system field---the struct 
printer.\n"
-           "This field comes before the user fields in the initializers 
passed\n"
-           "to @code{make-vtable-vtable} and @code{make-struct}, and thus 
works as\n"
-           "a third optional argument to @code{make-vtable-vtable} and a 
fourth to\n"
-           "@code{make-struct} when creating vtables:\n\n"
-           "If the value is a procedure, it will be called instead of the 
standard\n"
-           "printer whenever a struct described by this vtable is printed.\n"
-           "The procedure will be called with arguments STRUCT and PORT.\n\n"
-           "The structure of a struct is described by a vtable, so the vtable 
is\n"
-           "in essence the type of the struct.  The vtable is itself a struct 
with\n"
-           "a vtable.  This could go on forever if it weren't for the\n"
-           "vtable-vtables which are self-describing vtables, and thus 
terminate\n"
-           "the chain.\n\n"
-           "There are several potential ways of using structs, but the 
standard\n"
-           "one is to use three kinds of structs, together building up a 
type\n"
-           "sub-system: one vtable-vtable working as the root and one or 
several\n"
-           "\"types\", each with a set of \"instances\".  (The vtable-vtable 
should be\n"
-           "compared to the class <class> which is the class of itself.)\n\n"
-           "@lisp\n"
-           "(define ball-root (make-vtable-vtable \"pr\" 0))\n\n"
-           "(define (make-ball-type ball-color)\n"
-           "  (make-struct ball-root 0\n"
-           "          (make-struct-layout \"pw\")\n"
-           "               (lambda (ball port)\n"
-           "                 (format port \"#<a ~A ball owned by ~A>\"\n"
-           "                         (color ball)\n"
-           "                         (owner ball)))\n"
-           "               ball-color))\n"
-           "(define (color ball) (struct-ref (struct-vtable ball) 
vtable-offset-user))\n"
-           "(define (owner ball) (struct-ref ball 0))\n\n"
-           "(define red (make-ball-type 'red))\n"
-           "(define green (make-ball-type 'green))\n\n"
-           "(define (make-ball type owner) (make-struct type 0 owner))\n\n"
-           "(define ball (make-ball green 'Nisse))\n"
-           "ball @result{} #<a green ball owned by Nisse>\n"
-           "@end lisp")
-#define FUNC_NAME s_scm_make_vtable_vtable
+#if SCM_ENABLE_DEPRECATED == 1
+SCM
+scm_make_vtable_vtable (SCM user_fields, SCM tail_array_size, SCM init)
+#define FUNC_NAME "make-vtable-vtable"
 {
   SCM fields, layout, obj;
   size_t basic_size, n_tail, i, n_init;
@@ -656,7 +615,38 @@ SCM_DEFINE (scm_make_vtable_vtable, "make-vtable-vtable", 
2, 0, 1,
   return obj;
 }
 #undef FUNC_NAME
+#endif
+
+SCM
+scm_i_make_vtable_vtable (SCM user_fields)
+#define FUNC_NAME "make-vtable-vtable"
+{
+  SCM fields, layout, obj;
+  size_t basic_size;
+  scm_t_bits v;
 
+  SCM_VALIDATE_STRING (1, user_fields);
+
+  fields = scm_string_append (scm_list_2 (required_vtable_fields,
+                                         user_fields));
+  layout = scm_make_struct_layout (fields);
+  if (!scm_is_valid_vtable_layout (layout))
+    SCM_MISC_ERROR ("invalid user fields", scm_list_1 (user_fields));
+
+  basic_size = scm_i_symbol_length (layout) / 2;
+
+  obj = scm_i_alloc_struct (NULL, basic_size);
+  /* Make it so that the vtable of OBJ is itself.  */
+  SCM_SET_CELL_WORD_0 (obj, (scm_t_bits) SCM_STRUCT_DATA (obj) | 
scm_tc3_struct);
+
+  v = SCM_UNPACK (layout);
+  scm_struct_init (obj, layout, 0, 1, &v);
+  SCM_SET_VTABLE_FLAGS (obj,
+                        SCM_VTABLE_FLAG_VTABLE | SCM_VTABLE_FLAG_VALIDATED);
+
+  return obj;
+}
+#undef FUNC_NAME
 
 SCM_DEFINE (scm_make_vtable, "make-vtable", 1, 1, 0,
             (SCM fields, SCM printer),
@@ -1011,6 +1001,8 @@ scm_print_struct (SCM exp, SCM port, scm_print_state 
*pstate)
 void
 scm_init_struct ()
 {
+  SCM name;
+
   /* The first word of a struct is equal to `SCM_STRUCT_DATA (vtable) +
      scm_tc3_struct', and `SCM_STRUCT_DATA (vtable)' is 2 words after VTABLE by
      default.  */
@@ -1026,29 +1018,37 @@ scm_init_struct ()
   required_applicable_fields = scm_from_locale_string 
(SCM_APPLICABLE_BASE_LAYOUT);
   required_applicable_with_setter_fields = scm_from_locale_string 
(SCM_APPLICABLE_WITH_SETTER_BASE_LAYOUT);
 
-  scm_standard_vtable_vtable =
-    scm_make_vtable_vtable (scm_nullstr, SCM_INUM0, SCM_EOL);
-  scm_c_define ("<standard-vtable>", scm_standard_vtable_vtable);
+  scm_standard_vtable_vtable = scm_i_make_vtable_vtable (scm_nullstr);
+  name = scm_from_utf8_symbol ("<standard-vtable>");
+  scm_set_struct_vtable_name_x (scm_standard_vtable_vtable, name);
+  scm_define (name, scm_standard_vtable_vtable);
 
   scm_applicable_struct_vtable_vtable =
     scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
                      scm_list_1 (scm_make_struct_layout 
(required_vtable_fields)));
+  name = scm_from_utf8_symbol ("<applicable-struct-vtable>");
   SCM_SET_VTABLE_FLAGS (scm_applicable_struct_vtable_vtable,
                         SCM_VTABLE_FLAG_APPLICABLE_VTABLE);
-  scm_c_define ("<applicable-struct-vtable>", 
scm_applicable_struct_vtable_vtable);
+  scm_set_struct_vtable_name_x (scm_applicable_struct_vtable_vtable, name);
+  scm_define (name, scm_applicable_struct_vtable_vtable);
 
   scm_applicable_struct_with_setter_vtable_vtable =
     scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
                      scm_list_1 (scm_make_struct_layout 
(required_vtable_fields)));
+  name = scm_from_utf8_symbol ("<applicable-struct-with-setter-vtable>");
+  scm_set_struct_vtable_name_x 
(scm_applicable_struct_with_setter_vtable_vtable, name);
   SCM_SET_VTABLE_FLAGS (scm_applicable_struct_with_setter_vtable_vtable,
                         SCM_VTABLE_FLAG_APPLICABLE_VTABLE | 
SCM_VTABLE_FLAG_SETTER_VTABLE);
-  scm_c_define ("<applicable-struct-with-setter-vtable>", 
scm_applicable_struct_with_setter_vtable_vtable);
+  scm_define (name, scm_applicable_struct_with_setter_vtable_vtable);
 
   scm_c_define ("vtable-index-layout", scm_from_int (scm_vtable_index_layout));
   scm_c_define ("vtable-index-printer",
                scm_from_int (scm_vtable_index_instance_printer));
   scm_c_define ("vtable-offset-user", scm_from_int (scm_vtable_offset_user));
 #include "libguile/struct.x"
+#if SCM_ENABLE_DEPRECATED
+  scm_c_define_gsubr ("make-vtable-vtable", 2, 0, 1, scm_make_vtable_vtable);
+#endif
 }
 
 /*
diff --git a/libguile/struct.h b/libguile/struct.h
index 743e7ae..3072f24 100644
--- a/libguile/struct.h
+++ b/libguile/struct.h
@@ -180,7 +180,10 @@ SCM_API SCM scm_c_make_struct (SCM vtable, size_t n_tail, 
size_t n_inits,
 SCM_API SCM scm_c_make_structv (SCM vtable, size_t n_tail, size_t n_inits,
                                 scm_t_bits init[]);
 SCM_API SCM scm_make_vtable (SCM fields, SCM printer);
-SCM_API SCM scm_make_vtable_vtable (SCM extra_fields, SCM tail_array_size, SCM 
init);
+SCM_INTERNAL SCM scm_i_make_vtable_vtable (SCM extra_fields);
+#if SCM_ENABLE_DEPRECATED == 1
+SCM_DEPRECATED SCM scm_make_vtable_vtable (SCM extra_fields, SCM 
tail_array_size, SCM init);
+#endif
 SCM_API SCM scm_struct_ref (SCM handle, SCM pos);
 SCM_API SCM scm_struct_set_x (SCM handle, SCM pos, SCM val);
 SCM_API SCM scm_struct_vtable (SCM handle);
diff --git a/test-suite/tests/goops.test b/test-suite/tests/goops.test
index b864b24..1705ee8 100644
--- a/test-suite/tests/goops.test
+++ b/test-suite/tests/goops.test
@@ -1,6 +1,6 @@
 ;;;; goops.test --- test suite for GOOPS                      -*- scheme -*-
 ;;;;
-;;;; Copyright (C) 2001,2003,2004, 2006, 2008, 2009, 2011 Free Software 
Foundation, Inc.
+;;;; Copyright (C) 2001,2003,2004, 2006, 2008, 2009, 2011, 2012 Free Software 
Foundation, Inc.
 ;;;; 
 ;;;; This library is free software; you can redistribute it and/or
 ;;;; modify it under the terms of the GNU Lesser General Public
@@ -147,7 +147,9 @@
   (pass-if "struct vtable"
     ;; Previously, `class-of' would fail for nameless structs, i.e., structs
     ;; for which `struct-vtable-name' is #f.
-    (is-a? (class-of (make-vtable-vtable "prprpr" 0)) <class>)))
+    (is-a? (class-of (make-vtable
+                      (string-append standard-vtable-fields "prprpr")))
+           <class>)))
 
 
 (with-test-prefix "defining classes"
diff --git a/test-suite/tests/structs.test b/test-suite/tests/structs.test
index 55e0807..431a014 100644
--- a/test-suite/tests/structs.test
+++ b/test-suite/tests/structs.test
@@ -1,7 +1,7 @@
 ;;;; structs.test --- Structures.      -*- mode: scheme; coding: utf-8; -*-
 ;;;; Ludovic Courtès <address@hidden>, 2006-06-12.
 ;;;;
-;;;; Copyright (C) 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+;;;; Copyright (C) 2006, 2007, 2009, 2010, 2012 Free Software Foundation, Inc.
 ;;;;
 ;;;; This library is free software; you can redistribute it and/or
 ;;;; modify it under the terms of the GNU Lesser General Public
@@ -26,7 +26,8 @@
 ;;; Struct example taken from the reference manual (by Tom Lord).
 ;;;
 
-(define ball-root (make-vtable-vtable "pr" 0))
+(define ball-root
+  (make-vtable (string-append standard-vtable-fields "pr") 0))
 
 (define (make-ball-type ball-color)
   (make-struct ball-root 0
@@ -63,9 +64,10 @@
      (and (eq? (struct-vtable red) ball-root)
          (eq? (struct-vtable green) ball-root)
          (eq? (struct-vtable (make-ball red "Bob")) red)
+          (eq? (struct-vtable ball-root) <standard-vtable>)
 
          ;; end of the vtable tower
-         (eq? (struct-vtable ball-root) ball-root)))
+         (eq? (struct-vtable <standard-vtable>) <standard-vtable>)))
 
   (pass-if-exception "write-access denied"
      exception:struct-set!-denied
@@ -139,7 +141,7 @@
   ;; the program
   ;;
   (pass-if-exception "wrong type for `u' field" exception:wrong-type-arg
-    (let* ((vv (make-vtable-vtable "" 0))
+    (let* ((vv (make-vtable standard-vtable-fields))
           (v  (make-struct vv 0 (make-struct-layout "uw"))))
       (make-struct v 0 'x)))
 
@@ -150,7 +152,7 @@
   ;; SCM can cause a segv).
   ;;
   (pass-if-exception "no R/W/O for tail array" exception:bad-tail
-    (let* ((vv (make-vtable-vtable "" 0))
+    (let* ((vv (make-vtable standard-vtable-fields))
           (v  (make-struct vv 0 (make-struct-layout "pw"))))
       (make-struct v 123 'x))))
 


hooks/post-receive
-- 
GNU Guile



reply via email to

[Prev in Thread] Current Thread [Next in Thread]