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

Re: [Scheme-reports] eq? and eqv? for records

Sascha Ziemann <ceving@x> writes:

> On page 31 of R7RS draft 9 it is written:
> "On symbols, booleans, the empty list, pairs, non-empty
> strings, vectors, bytevectors, and records, eq? and eqv? are
> guaranteed to have the same behavior."
> And later on the same page:
> "On empty strings, vectors, bytevectors, and records, eq? may
> also behave differently from eqv?."
> Have eq? and eqv? the same behaviour for records or do they behave
> differently?
> The first sentence could also mean that eq? does the same for strings
> and records. But what is the record equivalent for an empty string?
> Does it exist?

I believe an empty record would be one without any fields:

(define-record-type <token>
  (make-token) token?)

Hrm, at first thought I would expect this to work for creating unique
objects that can be compared with `eq?' to test identity, the same way
`cons' (or `gensym' if available) is often used.  I suppose it is not
guaranteed to work that way, per R7RS-small.  However, that in turn
makes sense when I remind myself of the viewpoint that `eq?' is an
efficiency hack over `eqv?', and `eqv?' is a test for operational
equivalence; after all two immutable objects with identical contents
(including empty contents) are operationally equivalent and could be
made to be the same object in memory (as an optimization) even when
created through different calls to a constructor.

To be pedantically conformant to that viewpoint (though I know it
doesn't necessarily try to), R7RS-small should also allow immutable
records with identical contents to be `eq?' (and `eqv?'), and not
prescribe a #false return-value when testing their equivalence.  (All
other "container" data types have no way to be immutable other than
being literals, or empty, if I'm not mistaken, so this issue only
applies to record-types, since they can be defined to be immutable by
omitting mutators.)


Actually, reading sections 6.1 (`eqv?'), 3.4 (storage model), and 5.5
(record-type definitions), I cannot find the precise semantics for
record equivalence at all.  The `eqv?' definition says that if its
arguments are records, it returns #true iff they "denote the same
location in the store (section 3.4)", reading section 3.4 I see no
mention of records specifically, reading the part of section 5.5 that
explains the constructor (<constructor name>), the only thing I see that
might relate to section 3.4 is that it specifies the constructor to
return "a new record", but there is no mention of the store, locations,
or allocation.  Section 6 (standard procedures) says that "when a
procedure is said to return a /newly allocated/ object, it means that
the locations in the object are fresh."  The phrase "a new record"
doesn't seem clear enough.

I might be missing something but this seems like a nontrivial oversight;
in short, there seems to be no explicit specification that *any* two
different records must return #false when compared with `eqv?' (though
it might be obvious).

I would propose to add wording to the part of section 5.5 that explains
the constructor, specifying either that it must return a newly allocated
record for every call (the simple solution, going along well with other
wording in the document), or that it must do so only for mutable records
and immutable ones with distinct contents to all other records (not all
fields are `eqv?') and that immutable ones with identical contents need
not denote distinct locations.  (In the former option, I believe it is
clear enough that the special-casing of empty records "overrides" this
wording; the same thing goes for `make-vector', `make-string', etc.,
which also just say "newly allocated" and don't mention the empty

Or rather, I would propose that for the errata, since the draft is final
and it really is intuitively obvious that at the very least distinct
records (mutable and created with different calls to the constructor, or
immutable but having non-eqv? fields) must not be `eqv?'.

(By the way it comes to my attention that the phrase "newly allocated"
is used a few times prior to section 6 where it is described.  Section
3.4 speaks of situations where the report speaks of "storage being newly
allocated for a variable or object", perhaps that should be clarified to
make it obvious that the sole phrase "newly allocated" means the same
thing, and the redundant explanation in section 6 removed.)

Sorry for the long-winded e-mail, I discovered many things on-the-go and
didn't have the time to rewrite it to be shorter.


Scheme-reports mailing list