Shiro Kawai wrote:
> > > In other words, we make make-rtd behave
> > > functionally, meaning it returns eqv? objects for equivalent
> > > set of arguments.
> >
> > That could be done, but it's more complicated.
>
> Not necessarily. If simplicity is important, you can
> just return a new structure from make-rtd. When comparing
> rtds, the simplest way is to compare element-by-element
> (just like comparing complex numbers, for example. that's
> how "functional" objects should be compared, semantically.)
Element-by-element comparisons are more complicated than
pointer comparisons, even if you ignore performance.
If the comparison involves equality of the parent record
type, then the comparison involves recursion.
> If performance is important, complexity generally increases.
The performance of records is important. If programmers
can't rely on record accesses to be reasonably fast, then
they'll start to use vectors instead of records even when
records would otherwise be more appropriate.
> Using tables is one way to optimize comparison. If an
> implementation wish to use the table, I suppose it already
> has tables with weak references, hence inadvertent retention
> won't occur.
Hash tables with weak references aren't universal, and
may have drawbacks even in systems that have them.
> Another optimization strategy may be that the implementation
> calculates a hash value from rtd fields and cache it in an rtd.
Even when an integer hash matches, you'd still have to
perform the complicated comparison to confirm the match.
> Either way, it is an implementation detail.
Agreed.
> Do you still see disadvantages?
Yes. Using the "sufficiently clever implementation" idea
to pretend that performance and implementation complexity
don't matter has gotten language designers into a lot of
trouble in the past, and it did some harm even to the R6RS.
> What I think as an advantage is: I assume nongenerative rtds
> are the norm, and generative ones are exceptional. Putting
> the burden of specfying extra information (uid) to the
> rarer use case certainly has an advantage.
Okay, I'll admit that advantage.
On the other hand, I'm going to appeal to the "sufficiently
clever implementation" to this extent: Most record types
are likely to be defined at the top level of a library or
top-level program by straightforward, easy-to-recognize code.
Implementations that invoke each library only once (which
has other advantages as well) can treat that common special
case as though the definitions were non-generative. That's
just a simple source transformation.
To programmers, generative record types defined at top level
are equivalent to a non-generative record type defined at
top level, so neither default adds any extra burden for that
common case.
For record types that are not defined at top level, it is
unclear whether generative or non-generative definitions are
more common. My intuition says it's likely to depend upon
individual programmers' preferred styles, so no general rule
applies generally.
Will