Records
=======

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.

Jonathan Rees's define-record-type macro
----------------------------------------

 -- syntax: define-record-type

          (define-record-type RECORD-TYPE-NAME RECORD-TYPE-VARIABLE
            (CONSTRUCTOR CONSTRUCTOR-ARGUMENT ...)
            [PREDICATE]
            (FIELD-TAG FIELD-ACCESSOR [FIELD-MODIFIER])
            ...) lisp
          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 lisp

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, optimistic concurrency by logging in the current proposal.

Richard Kelsey's define-record-type macro
-----------------------------------------

 -- syntax: define-record-type

          (define-record-type TYPE-NAME
            (ARGUMENT-FIELD-SPECIFIER ...)
            (NONARGUMENT-FIELD-SPECIFIER ...))

              ARGUMENT-FIELD-SPECIFIER returns
                  FIELD-TAG              Immutable field
                | (FIELD-TAG)            Mutable field
              NONARGUMENT-FIELD-SPECIFIER returns
                  FIELD-TAG              Uninitialized field
                | (FIELD-TAG EXP)        Initialized with EXP's value lisp
          This 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 be
          set-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))) lisp

               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)) lisp

Record types
------------

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.)

 -- procedure: make-record-type name field-tags returns record-type-descriptor
 -- procedure: record-type? object returns boolean
     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.

 -- procedure: record-type-name rtype-descriptor returns symbol
 -- procedure: record-type-field-names rtype-descriptor returns symbol-list
     Accessors for the two record type descriptor fields.

 -- procedure: record-constructor rtype-descriptor argument-field-tags returns constructor-procedure
 -- procedure: record-predicate rtype-descriptor returns predicate-procedure
 -- procedure: record-accessor rtype-descriptor field-tag returns accessor-procedure
 -- procedure: record-modifier rtype-descriptor field-tag returns modifier-procedure
     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 and record-modifier return accessors and modifiers for records whose record type descriptor is RTYPE-DESCRIPTOR for the given fields.

 -- procedure: define-record-discloser rtype-descriptor discloser returns unspecific
     Defines the method by which records of type RTYPE-DESCRIPTOR are disclosed (see Writer).  This is also exported by define-record-types and defrecord.

 -- procedure: define-record-resumer rtype-descriptor resumer returns unspecified
     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 Suspending and resuming heap images, 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 Suspending and resuming heap images, 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 to usual-resumer is called.

The records-internal structure also exports these:

 -- record type: :record-type
     The record type of record types.

 -- procedure: disclose-record record returns disclosed
     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)) lisp

     or like so with Richard Kelsey's define-record-type macro:

          (define-record-type record-type
            (name field-names)
            ()) lisp

          Of course, in reality, these definitions would have severe problems
          with circularity of definition.

Low-level record manipulation
-----------------------------

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!

 -- procedure: make-record length init returns record
 -- procedure: record elt ... returns record
 -- procedure: record? object returns boolean
 -- procedure: record-length record returns integer
 -- procedure: record-ref record index returns value
 -- procedure: record-set! record index object returns unspecified
     Exact analogues of similarly named vector operation procedures.

 -- procedure: record-type record returns value
     This returns the record type descriptor of RECORD, ie the value of the slot at index 0 in RECORD.