[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
arguments.
Summary
-------
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)
(fields
(x mutable)
(y mutable)))
(define-type hash-table (pred hasher size)
(fields
(pred immutable)
(hasher immutable)
(data mutable (make-vector (nearest-prime size)))
(count mutable 0)))
-- Anton
[1]
http://mailman.iro.umontreal.ca/mailman/private/r6rs/2005-July/000761.html
More information about the R6RS
mailing list