Next: Suspending and resuming heap images, Previous: Reader & writer, Up: System facilities
Scheme48 provides several different levels of a record facility. Most programmers will probably not care about the two lower levels; the syntactic record type definers are sufficient for abstract data types.
At the highest level, there are two different record type definition
macros. Richard Kelsey's is exported from the defrecord
structure; Jonathan Rees's is exported from define-record-types
.
They both export a define-record-type
macro and the same
define-record-discloser
procedure; however, the macros are
dramatically different. Scheme48 also provides [SRFI 9], which is
essentially Jonathan Rees's record type definition macro with a slight
syntactic difference, in the srfi-9
structure. Note, however,
that srfi-9
does not export define-record-discloser
. The
difference between Jonathan Rees's and Richard Kelsey's record type
definition macros is merely syntactic convenience; Jonathan Rees's more
conveniently allows for arbitrary naming of the generated variables,
whereas Richard Kelsey's is more convenient if the naming scheme varies
little.
define-record-type
macro(define-record-type record-type-name record-type-variable (constructor constructor-argument ...) [predicate] (field-tag field-accessor [field-modifier]) ...)This defines record-type-variable to be a record type descriptor. Constructor is defined to be a procedure that accepts the listed field arguments and creates a record of the newly defined type with those fields initialized to the corresponding arguments. Predicate, if present, is defined to be the disjoint (as long as abstraction is not violated by the lower-level record interface) type predicate for the new record type. Each field-accessor is defined to be a unary procedure that accepts a record type and returns the value of the field named by the corresponding field-tag. Each field-modifier, if present, is defined to be a binary procedure that accepts a record of the new type and a value, which it assigns the field named by the corresponding field-tag to. Every constructor-argument must have a corresponding field-tag, though field-tags that are not used as arguments to the record type's constructor are simply uninitialized when created. They should have modifiers: otherwise they will never be initialized.
It is worth noting that Jonathan Rees's
define-record-type
macro does not introduce identifiers that were not in the original macro's input form.For example:
(define-record-type pare rtd/pare (kons a d) pare? (a kar) (d kdr set-kdr!)) (kar (kons 5 3)) => 5 (let ((p (kons 'a 'c))) (set-kdr! p 'b) (kdr p)) => b (pare? (kons 1 2)) => #t (pare? (cons 1 2)) => #f
There is also a variant of Jonathan Rees's define-record-type
macro for defining record types with fields whose accessors and
modifiers respect optimistic concurrency by logging in the current proposal.
define-record-type
macro(define-record-type type-name (argument-field-specifier ...) (nonargument-field-specifier ...)) argument-field-specifier --> field-tag Immutable field | (field-tag) Mutable field nonargument-field-specifier --> field-tag Uninitialized field | (field-tag exp) Initialized with exp's valueThis defines
type/
type-name to be a record type descriptor for the newly defined record type, type-name-maker
to be a constructor for the new record type that accepts arguments for every field in the argument field specifier list, type-name?
to be the disjoint type predicate for the new record type, accessors for each field tag field-tag by constructing an identifier type-name-
field-tag, and modifiers for each argument field tag that was specified to be mutable as well as each nonargument field tag. The name of the modifier for a field tag field-tag is constructed to beset-
type-name-
field-tag!
.Note that Richard Kelsey's
define-record-type
macro does concatenate & introduce new identifiers, unlike Jonathan Rees's.For example, a use of Richard Kelsey's
define-record-type
macro(define-record-type pare (kar (kdr)) (frob (mumble 5)))is equivalent to the following use of Jonathan Rees's macro
(define-record-type pare type/pare (%pare-maker kar kdr mumble) pare? (kar pare-kar) (kdr pare-kdr set-pare-kdr!) (frob pare-frob set-pare-frob!) (mumble pare-mumble set-pare-mumble!)) (define (pare-maker kar kdr) (%pare-maker kar kdr 5))
Along with two general record type definition facilities, there are
operations directly on the record type descriptors themselves, exported
by the record-types
structure. (Record type descriptors are
actually records themselves.)
Make-record-type
makes a record type descriptor with the given name and field tags.Record-type?
is the disjoint type predicate for record types.
Accessors for the two record type descriptor fields.
Constructors for the various procedures relating to record types.
Record-constructor
returns a procedure that accepts arguments for each field in argument-field-tags and constructs a record whose record type descriptor is rtype-descriptor, initialized with its arguments.Record-predicate
returns a disjoint type predicate for records whose record type descriptor is rtype-descriptor.Record-accessor
andrecord-modifier
return accessors and modifiers for records whose record type descriptor is rtype-descriptor for the given fields.
Defines the method by which records of type rtype-descriptor are disclosed (see Writer). This is also exported by
define-record-types
anddefrecord
.
Sets rtype-descriptor's record resumer to be resumer. If resumer is
#t
(the default), records of this type require no particular reinitialization when found in dumped heap images; if resumer is#f
, records of the type rtype-descriptor may not be dumped in heap images; finally, if it is a procedure, and the heap image is resumed with the usual image resumer, it is applied to each record whose record type descriptor is rtype-descriptor after the run-time system has been initialized and before the argument tousual-resumer
is called.
The records-internal
structure also exports these:
This applies record's record type descriptor's discloser procedure to record to acquire a disclosed representation; see Writer.
For expository purposes, the record type record type might have been
defined like so with Jonathan Rees's define-record-type
macro:
(define-record-type record-type :record-type (make-record-type name field-names) record-type? (name record-type-name) (field-names record-type-field-names))
or like so with Richard Kelsey's define-record-type
macro:
(define-record-type record-type (name field-names) ())
Of course, in reality, these definitions would have severe problems with circularity of definition.
Internally, records are represented very similarly to vectors, and as
such have low-level operations on them similar to vectors, exported by
the records
structure. Records usually reserve the slot at
index 0 for their record type descriptor.
Warning: The procedures described here can be very easily misused to horribly break abstractions. Use them very carefully, only in very limited & extreme circumstances!
Exact analogues of similarly named vector operation procedures.