Deprecating pair mutation #192
Labels
No labels
Batteries
Cleanup
Consent Docket
Environments
Foundations
Macrological Fascicle
Meta
Multiple proposals exist
Pie-in-the-sky ideas
Problems without solutions
Public Comment
Publications
Question
R6RS Compatibility
Resolution in draft
Specification exists
SRFI/RnRS spec exists
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: scheme/r7rs#192
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
It has been proposed that
set-car!
andset-cdr!
should have deprecation warnings attached to them like the one we plan to apply tostring-set!
.In principle, I’m not against this. But I feel it will be harder to justify in the report text than
string-set!
deprecation.R6RS’s rationale volume offers four motivations for its somewhat half-hearted deprecation of
set-car!
andset-cdr!
:(They are not numbered in the R6 text; I have numbered the list here for clarity.)
A general issue with all four of these is that they’re quite vaguely worded, especially 3 and 4, and to a lesser extent 1. (These points don’t explain why or how things are complicated by these. In the case of 1, the reader can at least refer to the specifications of
map
and friends to see how the specification of higher-order procedures that operate on lists has had to be made more complicated; 3 and 4 have no examples.) 2 also mentions by name an optimization I hadn’t previously heard of. I have no idea why the R6RS editors thought 4 was the case: I’ve never noticed any problems with implementing variadic procedures which would specifically be solved by forbidding their mutation.Another issue is that problems 1 to 3 are not unique to mutation of lists. As @johnwcowan likes to say, the argument proves too much. Why not forbid mutation of other structures too, such as vectors and records? Mutation complicates very many higher-order procedures, as well as reasoning about programs that use it. Experienced Schemers already know to be careful with mutation. I doubt they’ll be convinced this is an argument to move towards forbidding it.
Compare this situation to strings, where requiring both
string-set!
andstring-ref
to be efficient puts significant constraints on an implementation’s representation of strings, and programmers can easily appreciate the drawbacks involved. (Nobody likes UTF-32’s waste of at least 25% of memory per character.)The last point is actually one of the most important points.
Apply
and the implementation of rest arguments by the compiler suffer greatly (in terms of efficiency) because of the mutability of lists.Apply
has to copy a rest argument list in general; a procedure with a rest argument list cannot, in general, just forward it to callees.Code that uses
apply
often becomes accidentally quadratic because of this.See also https://legacy.cs.indiana.edu/~dyb/pubs/LaSC-3-3-pp229-244.pdf (which actually introduced
case-lambda
under a different name and which also proposed a much better rest argument facility not relying on actual lists, but which regrettably didn't make it into the Scheme standard)Point 4 alone is much stronger than any reason for deprecating
string-set!
simply because pairs and lists are found every where in Scheme programs and because they are deeply tied to the language through the rest argument machinery.[...]
The argument does not prove too much when one considers the context. Lists are often used in a functional context, yet Scheme does not truly provide such a functional context. The point is not that people ("experienced schemers") have to pay for mutation by being careful, but that they also have to pay (or the procedures they call) when they actually don't want to use mutation.
Again, the situation with strings is a relative sideshow.
I agree with this, and have referred to it in the past as the "variadic recursion bug". However, it can be resolved by making rest-argument lists immutable (i.e. it is an error to mutate them) rather than by making all pairs immutable. The CL standard says: "The value of a rest parameter is permitted, but not required, to share structure with the last argument to
apply
."This would only be fully resolved if it would also be an error to mutate any list given as an argument to
apply
.It would be very hard for a Scheme implementation to guard against these instances of an error.
This resolution would also not solve the other three points.
We could require that
immutablize!
(bad name) is performed byapply
on its final argument. As things stand, anyone who writes a procedure with variadic recursion must guard against it. But I was proposing something simpler: explicitly allowing variadic recursive functions to treat their list arguments as immutable. This means that the cost of copying is imposed in the (probably tiny) minority of cases where mutation of the rest-list is desired rather than the majority of cases where it is not.