This SRFI is currently in final status. Here
explanation of each status that a SRFI can hold. To provide input
on this SRFI, please send email
To subscribe to the list,
instructions. You can access previous messages via the mailing
SRFI 9 and the compatible R7RS-small provide Scheme with record
types. The basic problem that is solved by these record types is that
they allow the user to introduce new types, disjoint from all existing
types. The record type system described in this document is a
conservative extension to SRFI 9 and R7RS record types (in other words, the
define-record-type defined in this specification
can serve as the equally named keyword from SRFI 9 and R7RS and can thus
be safely exported from
(srfi 9) and
that is intended to
solve another fundamental problem, namely the introduction of subtypes.
No issues at present.
As mentioned in the abstract, the record type definitions of R7RS-small allow for the introduction of new disjoint types, called record types. Each value of such a record type denotes a set of locations, one location for each record field defined by the record type. Each field, that is the location corresponding to that field, can be either mutable or immutable depending on whether the record type definition defines a mutator procedure for that field or not. To give immutable fields a value, a suitable constructor procedure of the record type has to be defined and used.
What isn't specified by the record types of R7RS-small is a way to extend record types. Extending a record type means to create a new record type that extends the given record type by adding zero or more new fields to it. The newly created type is not disjoint to all existing types in the sense that it effectively becomes a subtype of the record type that is extended. In order to construct a value of an extended type, the constructor of the type that is extended has to be invoked on the way.
The purpose of this SRFI is to specify a syntactic extension to the record system of R7RS-small that allows extending record types in the manner described above. The constructor procedures that can be defined with the syntax of this SRFI are of a rather rigid form (for example, the first arguments of a constructor of a subtype have to correspond to the arguments of the constructor of the parent, if any). If constructors of a different signature are needed, it is expected that they are defined by the user using ordinary Scheme definitions and the constructor defined by the record type definition. Another syntactic layer on top of the record types defined here is also possible. The guiding principle of this proposal, however, is just to provide the primitives on which more sophisticated systems (like an object system with single inheritance) can be built.
This SRFI differs from related specifications like SRFI 131 in that it does not rely on the identity of field names in order to specify a constructor for record-subtypes. In SRFI 136, parent fields in a constructor specification are solely referred to by position. On the other hand, there hasn't been reached a consensus by the community yet whether parent field names in SRFI 131 are matched as symbols or identifiers (or rather whether the former is compatible with the semantics of R7RS). In fact, the main reason for developing SRFI 136 was that it is mostly agnostic to whether field names are symbols or identifiers.
Thus, SRFI 136 follows the R6RS's record system in that regard.
Without any further extension by further SRFIs or further revisions of R7RS, the syntactic interface makes the following guarantees:
This specification also provides a minimal procedural interface and very basic introspection facilities, on which more sophisticated systems like the one specified by SRFI 99 can be built. R7RS leaves it open whether the record type descriptor is bound by a record-type definition to a runtime object or a syntactic representation. In order to be able to provide introspection facilities already at the expansion level, in this specification the choice of a syntactic representation as a keyword has been made. Due to this choice, the record type descriptor cannot serve as a descriptor for the record type in the procedural interface. However, a runtime record-type descriptor can be extracted from the keyword to be used in the procedural interface.
This SRFI extends 7.1.6 of R7RS-small as follows:
<definition> -> <record-type definition> <record-type definition> -> (define-record-type <type spec> <constructor spec> <predicate spec> <field spec> ...) <type spec> -> <type name> -> (<type name> <parent>) <constructor spec> -> #f -> <constructor name> -> (<constructor name> <field name> ...) <predicate spec> -> #f -> <predicate name> <field spec> -> (<field name> <accessor name>) -> (<field name> <accessor name> <mutator name>) <parent> -> <keyword> -> #f <type name> -> <identifier> <constructor name> -> <identifier> <predicate name> -> <identifier> <accessor name> -> <identifier> <mutator name> -> <identifier> <field name> -> <identifier> -> #f
It also extends 7.1.3 of R7RS-small as follows:
<macro use> -> (<type name> (<keyword> <datum> ...)) -> (<type name>)
The semantics of a record type definition is the same as in R7RS-small except for the following additions:
The record-type definition macro-expands into a cluster of definitions that:
<type name>as the record-type descriptor for the new record-type;
From the keyword that is bound to the record-type descriptor, a runtime representation for the use in procedural interface defined below can be extracted.
A record type definition extends R7RS-small with the following additional options:
<parent>expression is specified and not
#f, then it must be an identifier bound to a record-type descriptor that serves as the parent record-type for the record-type being defined.
#fis specified for the constructor or predicate, then no constructor or predicate procedure is defined. (This is useful when the record-type being defined will be used as an abstract base class and has no immutable fields.)
#fis specified for a field name that field is effectively unnamed.
When a constructor spec is of the form
name> <field name> ...) and the parent's constructor
takes n arguments (if there is no parent constructor, the
constructor of the parent's parent is considered, and so on):
define-record-typeform. (Here, an argument corresponds to an accessor name as if it was a variable reference corresponding to a variable.)
<type name> be the record-type descriptor
for a record-type defined by:
(define-record-type (<type name> <parent>) <constructor spec> <predicate spec> <field spec> ...)Then the macro use
(<type name> (<keyword> <datum> ...))macro-expands into:
(<keyword> <datum> ... <parent> <field-spec> ...)(If the record-type does not have a parent,
#f.) Furthermore, the macro use
(<type name>)macro-expands into an expression that evaluates to an object that serves as a runtime record-type descriptor for the procedural interface (see below).
Rationale: This allows the introspection of the record type at
macro-expansion type. The arguments
<datum> are to support CPS-techniques in
macro programming. For example, a pattern matcher written
syntax-rules can support matching of record
instances and can get hold of the record-type structure at
macro-expansion time by using the macro
(<keyword> <datum> ...))
#t if and only if
obj is a record constructed by
one of the constructors defined by this specification.
#t if and only if
a runtime record-type descriptor.
Returns the runtime record-type descriptor of the record type of the
Returns a type predicate of the record type, for
rtd is the runtime record-type
Returns the name of the record-type, for
rtd is the runtime record-type
descriptor, as a symbol.
Returns the runtime record-type descriptor of the parent of the
record-type, for which
rtd is the runtime record-type descriptor,
#f if there is no parent.
Returns a list of three-element lists of the
(field-name accessor mutator)
corresponding to the fields (excluding those of parent record-types)
defined by the record-type, for
rtd is the runtime record-type descriptor, such
field nameis the name of the field as a symbol or
#fif it is unnamed;
accessoris an accessor defined for the field;
mutatoris a mutator defined for the field if it is mutable and
(make-record-type-descriptor name fieldspecs)
(make-record-type-descriptor name fieldspecs parent)
name evaluates to a symbol
parent evaluates to the
runtime record-type descriptor of a record type definition of
<parent> (if the argument
parent is omitted,
<parent> defaults to
fieldspecs evaluates to a list of field
specifiers, where each field specifier is either a
(mutable name), or
(make-record-type-descriptor name fieldspecs parent)evaluates to
(let () (define-record-type (<type name> <parent>) #f #f <field spec> ...) (<type name>))where each
<field spec>corresponds to a field specifier in
nameor a list of the form
(mutable name), the corresponding
(name accessor mutator), where accessor and mutator are fresh symbols
(immutable name), the corresponding
(name accessor), where accessor is a fresh symbol.
(make-record rtd field-vector)
Returns an instance of the record type, for
rtd is the runtime record-type
descriptor, whose fields (including those of parent record-types
with the fields of parent record-types coming first) are initialized
with the objects in the vector
field-vector in order. It is an error if the field-vector does not have as
many elements as there are fields. It is unspecified whether the vector is shared with
the newly created record.
The sample implementation is given as an R7RS library, which only relies on the bindings
(scheme base). In particular, it is implemented using only
syntax-rules macros and does not rely on more sophisticated/less beautiful macro facilities.
The sample implementation is accompanied with an implementation of SRFI 131 on top of the syntax and procedures defined in this SRFI. Using this implementation, SRFI 131 and SRFI 136 record-types can mutually inherit each other and can thus be mixed in a program. (Caveat: SRFI 131 matches field names as symbols while the provided sample implementation of SRFI 136 matches field names on the syntactic level as identifiers. Thus, SRFI 131 record-types can only reference fields of SRFI 136 parents in their constructors if they are not being renamed during macro expansion.)
As the shape of constructors between SRFI 131 and SRFI 136 is incompatible, a SRFI 136 record-type with a SRFI 131 parent behaves as if the parent's constructor spec was given by a single identifier (that is without any field names as arguments).
For demonstration purposes of SRFI 137, the provided sample implementation for SRFI 136 builds upon that SRFI 137.Source for the compatible SRFI 131 implementation.
Credit goes to all members of the Scheme Working Group 2, who participated in the discussion of record types in R7RS-large. Quite a lot of wording was copied verbatim from SRFI 131.
The author of this SRFI would also like to thank Sudarshan S Chawathe, Takashi Kato, and Jim Rees, whose participation on the mailing list was very helpful in bringing this SRFI into final shape.
Finally, the whole process of bringing this SRFI into life wouldn't have happened without the encouragement by John Cowan and the support of Arthur A. Gleckler.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.