Next: stdlib records inspection, Previous: stdlib records syntactic layer, Up: stdlib records [Index]
The procedural layer is provided by the (rnrs records procedural (6))
library.
Return a record-type descriptor (RTD) representing a record type distinct from all built–in types and other record types.
The name argument must be a symbol. It names the record type, and is intended purely for informational purposes and may be used for printing by the underlying Scheme system.
The parent argument must be either #f
or an RTD.
If it is an RTD, the returned record type, t, extends
the record type p represented by parent. An exception with
condition type &assertion
is raised if parent is sealed
(see below).
The uid argument must be either #f
or a symbol. If
uid is a symbol, the record–creation operation is
nongenerative i.e., a new record type is created only if no
previous call to make-record-type-descriptor
was made with the
uid. If uid is #f
, the record–creation operation is
generative, i.e., a new record type is created even if a previous
call to make-record-type-descriptor
was made with the same
arguments.
If make-record-type-descriptor
is called twice with the same
uid symbol, the parent arguments in the two calls must be
eqv?
, the fields arguments equal?
, the sealed?
arguments boolean–equivalent (both #f
or both true), and the
opaque? arguments boolean–equivalent. If these conditions are
not met, an exception with condition type &assertion
is raised
when the second call occurs. If they are met, the second call returns,
without creating a new record type, the same record–type descriptor (in
the sense of eqv?
) as the first call.
NOTE Users are encouraged to use symbol names constructed using the UUID namespace (for example, using the record–type name as a prefix) for the uid argument.
The sealed? flag must be a boolean. If true, the returned record type is sealed, i.e., it cannot be extended.
The opaque? flag must be a boolean. If true, the record type is
opaque. If passed an instance of the record type, record?
returns #f
. Moreover, if ‘record-rtd’ is called with an
instance of the record type, an exception with condition type
&assertion
is raised. The record type is also opaque if an
opaque parent is supplied. If opaque? is #f
and an opaque
parent is not supplied, the record is not opaque.
The fields argument must be a vector of field specifiers. Each
field specifier must be a list of the form (mutable name)
or a list of the form (immutable name)
. Each name must be
a symbol and names the corresponding field of the record type; the names
need not be distinct. A field identified as mutable may be modified,
whereas, when a program attempts to obtain a mutator for a field
identified as immutable, an exception with condition type
&assertion
is raised. Where field order is relevant, e.g.,
for record construction and field access, the fields are considered to
be ordered as specified, although no particular order is required for
the actual representation of a record instance.
The specified fields are added to the parent fields, if any, to
determine the complete set of fields of the returned record type. If
fields is modified after make-record-type-descriptor
has
been called, the effect on the returned RTD is unspecified.
A generative record–type descriptor created by a call to
make-record-type-descriptor
is not eqv?
to any
record–type descriptor (generative or nongenerative) created by another
call to make-record-type-descriptor
. A generative record–type
descriptor is eqv?
only to itself, i.e., (eqv? rtd1
rtd2)
if, and only if, (eq? rtd1 rtd2)
.
Also, two nongenerative record–type descriptors are eqv?
if, and
only if, they were created by calls to
make-record-type-descriptor
with the same uid arguments.
Return #t
if the argument is a record–type descriptor, #f
otherwise.
Return a record-constructor descriptor (or constructor
descriptor for short) that specifies a record constructor (or
constructor for short), that can be used to construct record
values of the type specified by rtd, and which can be obtained via
record-constructor
. A constructor descriptor can also be used to
create other constructor descriptors for subtypes of its own record
type. rtd must be a record–type descriptor. protocol must
be a procedure or #f
. If it is #f
, a default protocol
procedure is supplied.
If protocol is a procedure, it is handled analogously to the
protocol expression in a define-record-type
form.
If rtd is a base record type parent-constructor-descriptor
must be #f
. In this case, protocol is called by
record-constructor
with a single argument p. p is a
procedure that expects one argument for every field of rtd and
returns a record with the fields of rtd initialized to these
arguments. The procedure returned by protocol should call p
once with the number of arguments p expects and return the
resulting record as shown in the simple example below:
(lambda (p) (lambda (v1 v2 v3) (p v1 v2 v3)))
Here, the call to p returns a record whose fields are initialized
with the values of v1, v2, and v3. The expression
above is equivalent to (lambda (p) p)
. Note that the procedure
returned by protocol is otherwise unconstrained; specifically, it
can take any number of arguments.
If rtd is an extension of another record type parent-rtd and
protocol is a procedure, parent-constructor-descriptor must
be a constructor descriptor of parent-rtd or #f
. If
parent-constructor-descriptor is a constructor descriptor,
protocol is called by record-constructor
with a single
argument n, which is a procedure that accepts the same number of
arguments as the constructor of parent-constructor-descriptor and
returns a procedure p that, when called, constructs the record
itself. The p procedure expects one argument for every field of
rtd (not including parent fields) and returns a record with the
fields of rtd initialized to these arguments, and the fields of
parent-rtd and its parents initialized as specified by
parent-constructor-descriptor.
The procedure returned by protocol should call n once with the number of arguments n expects, call the procedure p it returns once with the number of arguments p expects and return the resulting record. A simple protocol in this case might be written as follows:
(lambda (n) (lambda (v1 v2 v3 x1 x2 x3 x4) (let ((p (n v1 v2 v3))) (p x1 x2 x3 x4))))
This passes arguments v1, v2, v3 to n for
parent-constructor-descriptor and calls p
with x1,
…, x4 to initialize the fields of rtd itself.
Thus, the constructor descriptors for a record type form a sequence of protocols parallel to the sequence of record–type parents. Each constructor descriptor in the chain determines the field values for the associated record type. Child record constructors need not know the number or contents of parent fields, only the number of arguments accepted by the parent constructor.
protocol may be #f
, specifying a default constructor that
accepts one argument for each field of rtd (including the fields
of its parent type, if any). Specifically, if rtd is a base type,
the default protocol procedure behaves as if it were (lambda
(p) p)
. If rtd is an extension of another type, then
parent-constructor-descriptor must be either #f
or itself
specify a default constructor, and the default protocol procedure
behaves as if it were:
(lambda (n) (lambda (v1 … vj x1 … xk) (let ((p (n v1 … vj))) (p x1 … xk))))
The resulting constructor accepts one argument for each of the record type’s complete set of fields (including those of the parent record type, the parent’s parent record type, etc.) and returns a record with the fields initialized to those arguments, with the field values for the parent coming before those of the extension in the argument list. (In the example, j is the complete number of fields of the parent type, and $k$ is the number of fields of rtd itself.)
If rtd is an extension of another record type and
parent-constructor-descriptor is #f
,
parent-constructor-descriptor is treated as if it were a
constructor descriptor for the parent rtd of rtd with a default
protocol.
Implementation responsibilities: If protocol is a procedure, the implementation must check the restrictions on it to the extent performed by applying it as described when the constructor is called. An implementation may check whether protocol is an appropriate argument before applying it.
(define rtd1 (make-record-type-descriptor 'rtd1 #f #f #f #f '#((immutable x1) (immutable x2)))) (define rtd2 (make-record-type-descriptor 'rtd2 rtd1 #f #f #f '#((immutable x3) (immutable x4)))) (define rtd3 (make-record-type-descriptor 'rtd3 rtd2 #f #f #f '#((immutable x5) (immutable x6)))) (define protocol1 (lambda (p) (lambda (a b c) (p (+ a b) (+ b c))))) (define protocol2 (lambda (n) (lambda (a b c d e f) (let ((p (n a b c))) (p (+ d e) (+ e f)))))) (define protocol3 (lambda (n) (lambda (a b c d e f g h i) (let ((p (n a b c d e f))) (p (+ g h) (+ h i)))))) (define cd1 (make-record-constructor-descriptor rtd1 #f protocol1)) (define cd2 (make-record-constructor-descriptor rtd2 cd1 protocol2)) (define cd3 (make-record-constructor-descriptor rtd3 cd2 protocol3)) (define make-rtd1 (record-constructor cd1)) (define make-rtd2 (record-constructor cd2)) (define make-rtd3 (record-constructor cd3)) (make-rtd3 1 2 3 4 5 6 7 8 9) ⇒ #<record with fields initialized to 3, 5, 9, 11, 15, 17>
Call the protocol of constructor-descriptor (as described
for make-record-constructor-descriptor
) and return the resulting
constructor constructor for records of the record type associated
with constructor-descriptor.
Return a procedure that, given an object obj, returns #t
if
obj is a record of the type represented by rtd, and #f
otherwise.
k must be a valid field index of rtd. The
record-accessor
procedure returns a one–argument procedure whose
argument must be a record of the type represented by rtd. This
procedure returns the value of the selected field of that record.
The field selected corresponds to the kth element (0–based) of
the fields argument to the invocation of
make-record-type-descriptor
that created rtd. Note that
k cannot be used to specify a field of any type rtd extends.
k must be a valid field index of rtd. The
record-mutator
procedure returns a two–argument procedure whose
arguments must be a record record r of the type represented by
rtd and an object obj. This procedure stores obj
within the field of r specified by k. The k argument
is as in record-accessor
. If k specifies an immutable
field, an exception with condition type &assertion
is raised.
The mutator returns unspecified values.
(define :point (make-record-type-descriptor 'point #f #f #f #f '#((mutable x) (mutable y)))) (define :point-cd (make-record-constructor-descriptor :point #f #f)) (define make-point (record-constructor :point-cd)) (define point? (record-predicate :point)) (define point-x (record-accessor :point 0)) (define point-y (record-accessor :point 1)) (define point-x-set! (record-mutator :point 0)) (define point-y-set! (record-mutator :point 1)) (define p1 (make-point 1 2)) (point? p1) ⇒ #t (point-x p1) ⇒ 1 (point-y p1) ⇒ 2 (point-x-set! p1 5) ⇒ unspecified (point-x p1) ⇒ 5 (define :point2 (make-record-type-descriptor 'point2 :point #f #f # f '#((mutable x) (mutable y)))) (define make-point2 (record-constructor (make-record-constructor-descriptor :point2 #f #f))) (define point2? (record-predicate :point2)) (define point2-xx (record-accessor :point2 0)) (define point2-yy (record-accessor :point2 1)) (define p2 (make-point2 1 2 3 4)) (point? p2) ⇒ #t (point-x p2) ⇒ 1 (point-y p2) ⇒ 2 (point2-xx p2) ⇒ 3 (point2-yy p2) ⇒ 4 (define :point-cd/abs (make-record-constructor-descriptor :point #f (lambda (new) (lambda (x y) (new (abs x) (abs y)))))) (define make-point/abs (record-constructor :point-cd/abs)) (point-x (make-point/abs -1 -2)) ⇒ 1 (point-y (make-point/abs -1 -2)) ⇒ 2 (define :cpoint (make-record-type-descriptor 'cpoint :point #f #f #f '#((mutable rgb)))) (define make-cpoint (record-constructor (make-record-constructor-descriptor :cpoint :point-cd (lambda (p) (lambda (x y c) ((p x y) (color->rgb c))))))) (define make-cpoint/abs (record-constructor (make-record-constructor-descriptor :cpoint :point-cd/abs (lambda (p) (lambda (x y c) ((p x y) (color->rgb c))))))) (define cpoint-rgb (record-accessor :cpoint 0)) (define (color->rgb c) (cons 'rgb c)) (cpoint-rgb (make-cpoint -1 -3 'red)) ⇒ (rgb . red) (point-x (make-cpoint -1 -3 'red)) ⇒ -1 (point-x (make-cpoint/abs -1 -3 'red)) ⇒ 1
Next: stdlib records inspection, Previous: stdlib records syntactic layer, Up: stdlib records [Index]