[R6RS] Record proposal syntax simplification

Anton van Straaten anton
Mon Aug 8 03:41:39 EDT 2005

I'd like to propose some changes to the record proposal, mainly related 
to the use of the 'mutable' and 'immutable' keywords.

To motivate my suggestions, I'll start with a question: within the 
explicit naming layer alone, what purpose do the keywords "mutable" and 
"immutable" serve?  They don't add any information, or disambiguate 
anything, because it's possible to tell whether a field is mutable or 
immutable by whether or not a mutator name is specified.

It could be argued that the presence of these keywords make the 
mutability status of a field more explicit to the reader of the code. 
However, the keywords have a low signal-to-noise ratio, since they 
communicate only a single bit of information that's already present in 
another form.  They also tend to obscure more important information, 
specifically the field names, which are buried between the mutability 
keywords and the accessor names.  In any non-trivial record definition, 
there's going to be a lot of repetition of the words MUTABLE and 
IMMUTABLE, but little value provided by them.

These keywords do have one clear rationale: they allow consistency 
between the two syntactic layers, so that code written for the implicit 
naming layer "extends gracefully", as Kent put it in [1], to the 
explicit naming syntax.

The changes proposed below preserve this graceful extension quality, 
while reducing redundancy and increasing readability in the record 
definition syntax.

To give a quick preview, I'm proposing that the syntax of the <field 
spec> clause be changed to conform to the following syntax:

Explicit layer:
   (<field name> (<accessor name> [<mutator name>]) [<init expression>])

Implicit layer:
   (<field name> {mutable | immutable} [<init expression>])

This involves two changes related to the mutability keywords, and a 
third change involving optional init expressions.  A more detailed 
description and rationale for these three changes is given below.

1. Explicit naming layer: drop mutability keyword

For the explicit naming layer, I propose that the mutability keywords be 
dropped entirely, and that the form of the <field-spec> clause be 
changed slightly, so that it takes one of the following two forms:

     (<field name> (<accessor name>) <init expression>)
     (<field name> (<accessor name> <mutator name>) <init expression>)

To illustrate the difference between the old and new syntaxes, here are 
some example definitions of simple field specifications  in each syntax:

   Current syntax                    Modified syntax
   --------------                    ---------------
   ((mutable x get-x) x)             (x (get-x) x)
   ((immutable y get-y set-y!) y)    (y (get-y set-y!) y)

The modified syntax is more concise, and has the desirable property that 
the field name in each <field spec> appears at the beginning of the 
expression, rather than between the mutability keyword and the accessor.

2. Implicit naming layer: move mutability keyword

Since the implicit naming layer doesn't explicitly specify accessor or 
mutator names, some way of specifying the mutability status of fields is 
still required.  The MUTABLE and IMMUTABLE keywords work for this 
purpose, but for consistency with the above change, they should be moved 
to after the <field name>, so that the <field spec> for the implicit 
naming layer takes one of the following two forms, in addition to the 
forms from the explicit layer:

     (<field name> mutable <init expression>)
     (<field name> immutable <init expression>)

To switch from implicit naming to explicit naming, the mutability 
keyword can simply be replaced by a parenthesized accessor name and 
(optional) mutator name.  The two syntaxes are entirely compatible, and 
can coexist with each other when the implicit naming layer is used. 
This satisfies the requirement that the implicit syntax can be 
gracefully extended into the explicit syntax.

Here's an example of the difference between the two implicit layer syntaxes:

   Current syntax          Modified syntax
   --------------          ---------------
   ((mutable x) x)         (x mutable x)
   ((immutable y) y)       (y immutable y)

The modified syntax is a little cleaner, and again, the field name 
appears at the beginning of the expression.

The proposal so far represents a pure syntax change to the current 
proposal, and doesn't add or subtract any features.  This change could 
be implemented without the change described below, and I believe it 
would be an improvement to the current syntax.

3. Optional init expressions

Since the purpose of the implicit naming layer is essentially one of 
convenience and conciseness, I think that the <init expression> in the 
<field spec> should be optional in that layer.

Actually, I would also support making init expressions optional in the 
explicit naming layer.  A particular reason for this is that it would 
bring the explicit naming layer syntax to a similar level of conciseness 
and convenience as SRFI 9.

When a field's init expression is omitted, its initial value would be 
determined in the same way as in SRFI 9, i.e. fields whose names are 
listed in the <formals> list will have the corresponding constructor 
argument as their initial value.  Kent described the same approach in [1].

In the case where a field without an init expression also has no 
corresponding formal with the same name, my preference is to make this 
an error. This will force all fields to be properly initialized, either 
explicitly via an init expression, or implicitly via the constructor 


With these changes, the explicit naming layer syntax becomes more 
concise and convenient, particularly if init expressions are optional in 
that layer.

The implicit naming layer doesn't benefit quite as much.  There are 
still possibilities for simplifying the implicit layer syntax to satisfy 
Marc's goals.  Some of these possibilities were described by Kent in 
[1], but they are beyond the scope of what I'm proposing here.

Here are some sample definitions, which make use of all of the above 
changes (including optional init expressions in the explicit layer). 
These can be compared to equivalent examples in the draft SRFI to see 
the differences involved.

; explicit naming layer example
(define-type (pare kons pare?) (x y)
   (fields (x (kar set-kar!))
           (y (kdr))))

; implicit layer examples

(define-type point (x y)
     (x mutable)
     (y mutable)))

(define-type hash-table (pred hasher size)
     (pred   immutable)
     (hasher immutable)
     (data   mutable (make-vector (nearest-prime size)))
     (count  mutable 0)))

-- Anton


More information about the R6RS mailing list