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

Programmer-defined data types



This is the proposal for adding records (aka programmer-defined data types,
aka opaque types) to Scheme, as approved by consensus at the first meeting
of BASH.  It is derived from discussion at that meeting and messages to
RRRS-Authors on 8 Jul 87 and 26 May through 7 Jun 88.

I apologize in advance for the verbosity of the description; no good
precision-preserving abbreviations occurred to me as I was writing it up.

We propose adding the following procedures to Scheme:

(MAKE-RECORD-TYPE type-name slot-names)

Returns a ``record-type descriptor'', a value representing a new data type,
disjoint from all others.  The type-name argument must be a string, but is
only used for debugging purposes (such as the printed representation of a
record of the new type).  The slot-names argument is a list of symbols
naming the ``slots'' of a record of the new type.  It is an error if the
list contains any duplicates.

(RECORD-CONSTRUCTOR rtd)

Returns a procedure for constructing new members of the type represented by
rtd.  The returned procedure accepts exactly as many arguments as there
were slot-names in the call to MAKE-RECORD-TYPE that created the type
represented by rtd; these are used, in order, as the initial values of
those slots in a new record, which is returned by the constructor
procedure.

(RECORD-PREDICATE rtd)

Returns a procedure for testing membership in the type represented by rtd.
The returned procedure accepts exactly one argument and returns a true
value if the argument is a member of the indicated record type; it returns
a false value otherwise.

(RECORD-ACCESSOR rtd slot-name)

Returns a procedure for reading the value of a particular slot of a member
of the type represented by rtd.  The returned procedure accepts exactly one
argument which must be a record of the appropriate type; it returns the
current value of the slot named by the symbol slot-name in that record.
The symbol slot-name must be a member of the list of slot-names in the call
to MAKE-RECORD-TYPE that created the type represented by rtd.

(RECORD-UPDATER rtd slot-name)

Returns a procedure for writing the value of a particular slot of a member
of the type represented by rtd.  The returned procedure accepts exactly two
arguments: a record of the appropriate type and an arbitrary Scheme value;
it modifies the slot named by the symbol slot-name in that record to
contain the given value.  The returned value of the updater procedure is
unspecified.  The symbol slot-name must be a member of the list of
slot-names in the call to MAKE-RECORD-TYPE that created the type
represented by rtd.

(RECORD? obj)

Returns a true value if obj is a record of any type and a false value
otherwise.

(RECORD-TYPE-DESCRIPTOR record)

Returns a record-type descriptor representing the type of the given record.
That is, for example, if the returned descriptor were passed to
RECORD-PREDICATE, the resulting predicate would return a true value when
passed the given record.  Note that it is not necessarily the case that the
returned descriptor is the one that was passed to RECORD-CONSTRUCTOR in the
call that created the constructor procedure that created the given record.

(RECORD-TYPE-NAME rtd)

Returns the type-name associated with the type represented by rtd.  The
returned value is EQV? to the type-name argument given in the call to
MAKE-RECORD-TYPE that created the type represented by rtd.

(RECORD-TYPE-SLOT-NAMES rtd)

Returns a list of the symbols naming the slots in members of the type
represented by rtd.  The returned value is EQUAL? to the slot-names
argument given in the call to MAKE-RECORD-TYPE that created the type
represented by rtd.

=====================
Notes on the proposal
=====================

[Some of the notes below are taken from the discussion in 1988.]

-- The only significant difference between this proposal and the one made
by Jonathan Rees in his message of 26 May 88 is the inclusion of procedures
to ``inspect'' records.  These procedures were referred to as
``abstraction-breaking'' in Jonathan's proposal.

-- The procedure RECORD? is necessary to allow reliable use of the
procedure RECORD-TYPE-DESCRIPTOR.

-- The type-name argument to MAKE-RECORD-TYPE is constrained to be a string
in order to allow experimentation with interesting semantics for other
kinds of values there.  One possibility raised in the discussion in 1988
was some kind of a ``handler'' procedure, as in T objects.

-- We do not propose any general macro for the definition of record types.
The feeling is that this is not easy to do in a way that is both elegant
and sufficiently flexible.  Once we have macros, the primitives above
should be sufficient for portable experimentation.

-- Should there be a RECORD-COPIER procedure?  Some folks would like to
have one for performance and convenience; others point out that a copier
for any particular type is easy to write.  In fact, given the inspection
primitives above, one can even write a somewhat slow but general record
copying procedure that works on all types.

-- The issues of subtyping and inheritance, print methods, and integration
with modules and/or
environments (e.g. Pascal's WITH construct) have been purposely avoided in
order to achieve more rapid consensus.  Designs for adding single
inheritance appeared in the discussion in 1988.

-- A case can be made that constructor procedures should take no arguments
and leave all slots in new records uninitialized.  There appear to be
advantages to both points of view.

-- It is probably easy to agree on how EQ? and EQV? treat records; they
should be treated in the same way as pairs, vectors, and strings.  The
consensus of those I've spoken to concerning EQUAL? is that it should be
equivalent to EQV? on records, instead of treating them as it treats
vectors, pairs, and strings.  I have no opinion on the subject and look
forward to hearing any alternative points of view.

	Pavel