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

Programmer-defined data types, last (?) version



Morry Katz suggested that the field-names argument to MAKE-RECORD-TYPE be
spread out, as the 2nd through nth arguments.  I agree with Chris Hanson in
his opposition to this, primarily because I want to be able to extend this
functionality with extra, optional arguments to MAKE-RECORD-TYPE (e.g., in
Cedar Scheme, an optional parent rtd and printing procedure can be given).

In private mail, Alan Bawden asked for a more explicit statement concerning
the order of arguments to record updaters (it is as in SET-CAR!, with the
record to be changed followed by the new value for the field).  I have done
this below.

Alan also asked for more information about the result of applying RECORD?
to various types of values, such as pairs, promises, numbers, etc.  I have
updated its description to say that RECORD? may return true for any Scheme
value; of course, if it does so, then RECORD-TYPE-DESCRIPTOR will also be
applicable to that value and will return an ``appropriate'' record-type
descriptor.  I also added a note to the effect that the type of descriptors
is not necessarily disjoint from the other types in Scheme.

Jonathan Rees points out that, given the optionality of the second argument
to RECORD-CONSTRUCTOR, it is gratuitous to have RECORD-TYPE-FIELD-NAMES
return some random permutation of the original list.  I agree and have
changed the description back to its previous form, specifying that the
resulting list is EQUAL? to the one given when the type was created.

Here is the third and, I dare to hope, final version of the proposal.
Will, does this look like consensus?

	Pavel

=====================
We propose adding the following procedures to Scheme:

(MAKE-RECORD-TYPE type-name field-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 field-names argument is a list of symbols
naming the ``fields'' of a record of the new type.  It is an error if the
list contains any duplicates.  It is unspecified how record-type
descriptors are represented.

(RECORD-CONSTRUCTOR rtd [field-names])

Returns a procedure for constructing new members of the type represented by
rtd.  The returned procedure accepts exactly as many arguments as there are
symbols in the given list, field-names; these are used, in order, as the
initial values of those fields in a new record, which is returned by the
constructor procedure.  The values of any fields not named in that list are
unspecified.  The field-names argument defaults to the list of field-names
in the call to MAKE-RECORD-TYPE that created the type represented by rtd;
if the field-names argument is provided, it is an error if it contains any
duplicates or any symbols not in the default list.

(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 field-name)

Returns a procedure for reading the value of a particular field 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 field named by the symbol field-name in that record.
The symbol field-name must be a member of the list of field-names in the
call to MAKE-RECORD-TYPE that created the type represented by rtd.

(RECORD-UPDATER rtd field-name)

Returns a procedure for writing the value of a particular field of a member
of the type represented by rtd.  The returned procedure accepts exactly two
arguments: first, a record of the appropriate type, and second, an
arbitrary Scheme value; it modifies the field named by the symbol
field-name in that record to contain the given value.  The returned value
of the updater procedure is unspecified.  The symbol field-name must be a
member of the list of field-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.  Note that RECORD? may be true of any Scheme value; of course,
if it returns true for some particular value, then RECORD-TYPE-DESCRIPTOR
is applicable to that value and returns an appropriate descriptor. 

(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-FIELD-NAMES rtd)

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

=====================
Notes on the 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 May and
June of 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.

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

-- EQ? and EQV? treat records in the same way as they do pairs, vectors,
and strings.  EQUAL? is equivalent to EQV? on records.