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

structures



The following outlines a facility for defining new record types.  Such a
facility could be implemented using whatever we come up with for macros,
and PROJECT/INJECT/IN? as described in Will's minutes from the lunch
meeting at the '86 Lisp conference.  I am proposing the functionality
described (and implied), not the particular names.

Related issues are modules, types, and object-oriented programming.
This proposal may be premature if we haven't addressed these,
or it may be a stop-gap until we do.

DEFINE-RECORD-TYPE defines a new disjoint record type which has a fixed set
of named fields.  DEFINE-RECORD-TYPE defines procedures for making
instances of the type, and accesssing and assigning the fields of the
instances.  DEFINE-RECORD-TYPE also defines a predicate which returns
true only for instances of the type defined.

The simplest syntax for DEFINE-RECORD-TYPE is 

  (DEFINE-RECORD-TYPE typeName fieldName ...)

This would define the procedures 

     MAKE-<typeName>
     <typeName>?
     <typeName>-<fieldName>       (for each field)
     SET-<typeName>-<fieldName>!  (for each field)

---------------- Locality of names

Given that DEFINE-RECORD-TYPE is making definitions, where are these
definitions allowed, and what is the scope of these names?
Here are two possibilities.  Sketchy implementations illustrate.

1) Use syntactic extension and internal defines to provide local names.

(define-record-type emp name age) == 
    (begin (define make-emp (lambda () ...))
	   (define emp? (lambda (x) ...))
	   (define emp-name (lambda (emp) ...))
	   (define emp-age (lambda (emp) ...))
	   (define set-emp-name! (lambda (emp name) ...))
	   (define set-emp-age! (lambda (emp age) ...))
	   )

DEFINE-RECORD-TYPE form at top level would define the procedures globally;
but at the beginning of a <body> would define the procedures locally.  This
assumes that code generated by macros works the same way as "source" code.

2) Provide a procedural interface to make new record types, don't depend
on internal define.  DEFINE-RECORD-TYPE is one possible syntactic
extension which uses MAKE-RECORD-TYPE, a procedure.  This approach could be 
combined with the first.

(define-record-type emp name age) == 
   (begin
      (define make-emp '#!unspecified)
      (define emp?     '#!unspecified)
      (define emp-name '#!unspecified)
      ...
      (let ((new-record-type-frob (make-record-type 'emp '(name age))))
	(set! make-emp (record-type-constructor new-record-type-frob))
	(set! emp?     (record-type-predicator new-record-type-frob))
	(let ((selectors (record-type-selectors new-record-type-frob))
	      (assigners (record-type-assigners new-record-type-frob)))
	  (set! emp-name (record-type-selector selectors 0))
	  (set! emp-age  (record-type-selector selectors 1))
	  (set! set-emp-name! (record-type-assigner assigners 0))
	  (set! set-emp-age!  (record-type-assigner assigners 1))
	  ))))

This approach provides an interface which does not force particular names
on the client.  

---------------- Initializers

There are many possible enhancements that can be made to this
simple form of DEFINE-RECORD-TYPE.  Record facilities often provide
some way to do some form of initialization.

Some possibilities:

  - Fields are initialized to values passed to the constructor.  
    Either require that a value be passed for each field, or have
    some indication for each field in the DEFINE-RECORD-TYPE form 
    that the constructor will or will not be passed a value with which
    to initialize the field.

  - An initial value for each or any field may given in the 
    DEFINE-RECORD-TYPE form.  The expression for an initial value might be
    evaluated one time, or once per call to the constructor.  If not the
    latter, when is the expression evaluated?  

What is the syntax for any of this? 

---------------- Other issues

What is the name? DEFINE-STRUCTURE, DEFINE-STRUCTURE-TYPE, DEFSTRUCT

READ and WRITE syntax.

Unitialized fields - it "is an error" to access an uninitialized field?

Do we want to say anything about redefinition?  If you load a file
containing a DEFINE-RECORD-TYPE, say for EMPLOYEE, are existing instances of 
EMPLOYEE still going to answer true to EMPLOYEE? after you reload
the file?

Do we want to support variant records in any way?

I think there is a temptation to featurize a record package to compensate
for the lack of strong types.

-- Norman
-------