Editorial fixes for Draft 9

32 views
Skip to first unread message

Alexey Radul

unread,
May 11, 2013, 10:27:53 AM5/11/13
to scheme-reports-wg1
Dear WG1,

In reading through Draft 9 for acceptability, I came across a number
of little mistakes and confusions that we should correct. A handful
are just plain typos, and there are a few places where our text does
not perfectly codify our intent or existing practice. All the changes
needed to fix these issues seem to me to be purely editorial.

- Typo [p.27]. The last example in the first block of examples of
quasiquotation is missing the symbol "list" in the result.
Should be
(let ((foo `(foo bar)) (@baz `baz))
`(list ,@foo , @baz))
==> (list foo bar baz) ; <--
(Either that, or the symbol "list" should be removed from the input)

- I assume someone ran the library example program [pp.28-29] in Chibi
and confirmed that it works as expected?

- equal? of records [p.31] is implicitly unspecified. Should it be
mentioned that it is explicitly unspecified, to prevent readers from
assuming that records appear in one or the other of the lists of
types that appear in the specification of equal?, or from having to
do a double-take to notice that it is absent from both of them? Or
was implicit unspecification an intentional choice that I have
forgotten?

- Presentation of symbol identity [p.43]. Why do we describe symbol
identity in terms of eqv? in the text, but use eq? in the examples?
Yes, I know that eq? and eqv? are specified to have the same
behavior on symbols, but unless the stylistic disagreement is an
intentional reminder of that fact, I suggest using one of them
consistently; and I specifically suggest using eq?, because of the
general principle that eq? implies eqv?.

- Additional character names [p.44]. We didn't specify whether
implementations are permitted to define new character names that
begin with "x". If the remaining characters in the name happened to
be taken from the set [a-f0-9], such a name would give rise to an
ambiguity. This problem is only mildly fanciful: one could choose
to represent an set of icons as a (non-unicode) character set, and
one could choose to give names to the icons, which one could prefix
with "x" to distinguish them from "normal" characters, leading to a
problem with the name #\xbeef . It would be advisable not to rule
out all extra names starting with "x", however, because we should
admit #\xi as a name for the greek letter. Perhaps change
"Implementations are free to add other names." to "Implementations
are free to add other names, so long as those names are not of the
form x[a-fA-F0-9]+ , which would conflict with hex escapes."

- Character comparison [p.44]. This section is written assuming that
an implementation only supports a subset of Unicode, and is a bit
hard to interpret for non-Unicode characters. We should mention
what restrictions, if any, we impose on the comparison order of any
non-Unicode characters that an implementation might support, or
clarify that the restrictions we do impose apply only to Unicode
characters.

Are non-Unicode characters required to all be greater or less than
the Unicode characters? Are all characters in an implementation
required to form a total order under char<?, or only the Unicode
ones? At the very least, do we demand that char=? never return #t
when its arguments contain a Unicode character and a non-Unicode
character? (Not doing so would be troubling to me.) We might
specify that char<? and friends behave like
(define (char<? . args)
(apply < (map char->integer args)))
which is something our specification already implies for Unicode
characters.

- Stylistic uniformity on characters forbidden from strings [pp.45-47]
We list make-string, string, string-set!, and string-fill! but not
list->string as procedures to which it is an error to pass
characters that are forbidden in strings. In the specification of
string-fill! but not the others we repeat the injunction against
forbidden characters. I think we should either include that
injunction everywhere it applies or nowhere (and rely on the listing
on p.45); or, since in the case of list->string it is not a
forbidden character that is an argument but a list of them, omit
that one from the listing but write explicitly in its specification
that it is an error if any element of the list is a character
forbidden in strings.
- The same comment applies to vector->string [p.48], but with even
greater force because it is farther away from the discussion of
strings.
- It should also be an error if the procedure passed to string-map
[p.50] returns a character that is forbidden in strings. This one
we probably should mention explicitly.
- The same comment applies to read-string [p.57] because read-char
can in principle produce a character that is forbidden in strings.

- Typo [p.47]. string-copy! should copy to a *string* to (not a
bytevector).

- Grammar [pp.47,49]. "[example vector] can be written as *follows*:"
- Same problem for the example bytevector on p.49.

- Do map and friends [pp.50-51] always return newly allocated results?
For example, it's not too hard to write an otherwise-valid
definition of map where
(let ((one '(1 6 1 8 0 3))
(two '(1 4 1 4 2 1)))
(eqv? one (map (lambda (x y) x) one two)))
==> #t
and one might even want that, to save space. There are of course
more complicated examples where the result of a map could share list
structure with the tail of one of its inputs, as long as the
procedure being mapped returned those elements unchanged.

- Newly allocated empty objects [pp.41-50]. In the descriptions of
many procedures that return lists, strings, vectors, and
bytevectors, we require that the result be newly allocated, even
though elsewhere we specifically require all empty lists to be the
same object, so that it is impossible to allocate a new empty list.
We also permit all empty strings, vectors, and bytevectors to be the
same object respectively, so that in a given implementation it may
be impossible to allocate a new empty string, vector, or bytevector.
In the case of lists, this makes the standard inconsistent, and in
the case of other types, it specifies something we probably did not
intend.

Probably the easiest way to fix this is to add a clause somewhere in
the storage model section explicitly exempting empty objects from
requirements of being newly allocated. Do we actually define the
concept "newly allocated object" anywhere? We could also fix this
by altering the wording of each allocating procedure so that it is
not required to allocate a new result if it is empty. This affects:
- (make-list 0)
- (list)
- (reverse '())
- (list-copy '()) (Already exempts non-lists, but '() is a list)
- (substring "anything" 5 5)
- (string-copy "anything" 4 4)
- (make-string 0)
- (string)
- (string-append)
- (string->list "") and (list->string '())
- (make-vector 0)
- (vector)
- (vector->list #()) and (list->vector '())
- (vector->string #()) and (string->vector "")
- (vector-copy #()) or (vector-copy #(3 1 4 1 5 9) 3 3)
- (vector-append)
- (make-bytevector 0)
- (bytevector)
- (bytevector-copy #u8()) or (bytevector-copy #u8(2 7 1 8 2 8) 2 2)
- (bytevector-append)
- (utf8->string #u8()) ; Or whatever is the encoding of an empty string
- (string->utf8 "")
- The constructors of any user-defined record types that have no
fields [p.27]
- map and friends [p.50-51], if they are specified to return newly
allocated results per the previous point.

Best,
~Alexey

John Cowan

unread,
May 11, 2013, 12:38:38 PM5/11/13
to scheme-re...@googlegroups.com
Alexey Radul scripsit:

> In reading through Draft 9 for acceptability, I came across a number
> of little mistakes and confusions that we should correct. A handful
> are just plain typos, and there are a few places where our text does
> not perfectly codify our intent or existing practice. All the changes
> needed to fix these issues seem to me to be purely editorial.

Thank you very much for this thorough review. I'm making all changes
on the draft-10 branch.

> - Typo [p.27]. The last example in the first block of examples of
> quasiquotation is missing the symbol "list" in the result.

Fixed.

> - I assume someone ran the library example program [pp.28-29] in Chibi
> and confirmed that it works as expected?

It actually doesn't work for me. Can someone else try it?

> - equal? of records [p.31] is implicitly unspecified. Should it be
> mentioned that it is explicitly unspecified, to prevent readers from
> assuming that records appear in one or the other of the lists of
> types that appear in the specification of equal?, or from having to
> do a double-take to notice that it is absent from both of them? Or
> was implicit unspecification an intentional choice that I have
> forgotten?

That's the purpose of the "in all other cases" clause. It allows
implementations to treat `eqv?` and `equal?` either differently or the
same on records. The idea is that (modulo circularity) implementations
should have to change their definition of `equal?` for R7RS compliance.
If existing code expects `equal?` to descend through records, fine;
if it expects `equal?` to be `eqv?` on records, fine; in either case
such code is not portable.

No change here.

> - Presentation of symbol identity [p.43]. Why do we describe symbol
> identity in terms of eqv? in the text, but use eq? in the examples?

Fixed to use eqv? in the examples.

> - Additional character names [p.44].

See separate posting.

> - Character comparison [p.44]. This section is written assuming that
> an implementation only supports a subset of Unicode, and is a bit
> hard to interpret for non-Unicode characters.

I have rewritten this as "These procedures return #t if the results
of passing their arguments to char->integer are respectively equal,
monotonically increasing, monotonically decreasing, monotonically
non-decreasing, or monotonically non-increasing." This wording defers to
the definition of `char->integer`, which specifies that all non-Unicode
characters correspond to integers greater than any Unicode scalar value.

> - Stylistic uniformity on characters forbidden from strings [pp.45-47]
> We list make-string, string, string-set!, and string-fill! but not
> list->string as procedures to which it is an error to pass
> characters that are forbidden in strings.

Fixed.

> In the specification of string-fill! but not the others we repeat
> the injunction against forbidden characters. I think we should
> either include that injunction everywhere it applies or nowhere.

Added everywhere.

> - The same comment applies to vector->string [p.48], but with even
> greater force because it is farther away from the discussion of
> strings.

Already in place, but added this to the list in 6.7 with a
cross-reference.

> - It should also be an error if the procedure passed to string-map
> [p.50] returns a character that is forbidden in strings. This one
> we probably should mention explicitly.
> - The same comment applies to read-string [p.57] because read-char
> can in principle produce a character that is forbidden in strings.

Added (these are not domain errors) and added to the list as well.

Finally, I have added utf8->string to the list as well.

> - Typo [p.47]. string-copy! should copy to a *string* to (not a
> bytevector).

Fixed.

> - Grammar [pp.47,49]. "[example vector] can be written as *follows*:"
> - Same problem for the example bytevector on p.49.

Fixed.

> - Do map and friends [pp.50-51] always return newly allocated results?

See separate posting.

> - Newly allocated empty objects [pp.41-50]. [...]
> Probably the easiest way to fix this is to add a clause somewhere in
> the storage model section explicitly exempting empty objects from
> requirements of being newly allocated.

I rewrote the relevant passage thus:

Whenever this report speaks of storage being newly allocated for
a variable or object, what is meant is that an appropriate number
of locations are chosen from the set of locations that are not in
use, and the chosen locations are marked to indicate that they
are now in use before the variable or object is made to denote
them. Notwithstanding this, it is understood that the empty
list cannot be newly allocated, because it is a unique object.
It is also understood that empty strings, empty vectors, and
empty bytevectors, which contain no locations, may or may not
be newly allocated.

> We could also fix this by altering the wording of each allocating
> procedure so that it is not required to allocate a new result if it
> is empty.

Not going there, thanks. In any case, your list omits `(read-string 0)`
and `(read-bytevector 0)`, and perhaps other cases too.

--
Being understandable rather than obscurantist poses certain
risks, in that one's opinions are clear and therefore | John Cowan
falsifiable in the light of new data, but it has the | co...@ccil.org
advantage of encouraging feedback from others. --James A. Matisoff

Alexey Radul

unread,
May 11, 2013, 2:35:38 PM5/11/13
to scheme-re...@googlegroups.com
On Sat, May 11, 2013 at 12:38 PM, John Cowan <co...@mercury.ccil.org> wrote:
> Alexey Radul scripsit:
>> - Character comparison [p.44]. This section is written assuming that
>> an implementation only supports a subset of Unicode, and is a bit
>> hard to interpret for non-Unicode characters.
>
> I have rewritten this as "These procedures return #t if the results
> of passing their arguments to char->integer are respectively equal,
> monotonically increasing, monotonically decreasing, monotonically
> non-decreasing, or monotonically non-increasing." This wording defers to
> the definition of `char->integer`, which specifies that all non-Unicode
> characters correspond to integers greater than any Unicode scalar value.

Sounds good.

>> - Newly allocated empty objects [pp.41-50]. [...]
>> Probably the easiest way to fix this is to add a clause somewhere in
>> the storage model section explicitly exempting empty objects from
>> requirements of being newly allocated.
>
> I rewrote the relevant passage thus:
>
> Whenever this report speaks of storage being newly allocated for
> a variable or object, what is meant is that an appropriate number
> of locations are chosen from the set of locations that are not in
> use, and the chosen locations are marked to indicate that they
> are now in use before the variable or object is made to denote
> them. Notwithstanding this, it is understood that the empty
> list cannot be newly allocated, because it is a unique object.
> It is also understood that empty strings, empty vectors, and
> empty bytevectors, which contain no locations, may or may not
> be newly allocated.

Sounds good.

>> We could also fix this by altering the wording of each allocating
>> procedure so that it is not required to allocate a new result if it
>> is empty.
>
> Not going there, thanks. In any case, your list omits `(read-string 0)`
> and `(read-bytevector 0)`, and perhaps other cases too.

I didn't say my list was exhaustive :)

~Alexey

Alex Shinn

unread,
May 30, 2013, 7:58:38 AM5/30/13
to scheme-re...@googlegroups.com
On Sun, May 12, 2013 at 1:38 AM, John Cowan <co...@mercury.ccil.org> wrote:
> - I assume someone ran the library example program [pp.28-29] in Chibi
>   and confirmed that it works as expected?

It actually doesn't work for me.  Can someone else try it?

I had tested it before including it, and double checked now,
it runs fine.  You do have to fixup the TeX escapes though.

-- 
Alex

John Cowan

unread,
May 30, 2013, 8:08:30 AM5/30/13
to scheme-re...@googlegroups.com
Alex Shinn scripsit:

> I had tested it before including it, and double checked now,
> it runs fine. You do have to fixup the TeX escapes though.

Ah, of course. ~~ headslap ~~

--
There is no real going back. Though I John Cowan
may come to the Shire, it will not seem co...@ccil.org
the same; for I shall not be the same. http://www.ccil.org/~cowan
I am wounded with knife, sting, and tooth,
and a long burden. Where shall I find rest? --Frodo
Reply all
Reply to author
Forward
0 new messages