29
78
Fork
You've already forked r7rs
2

Contagious mutability #74

Open
opened 2022年04月21日 02:45:00 +02:00 by johnwcowan · 2 comments

One case I didn't discuss before is that of mutability contagion. R7RS-small backward compat requires that if all arguments are mutable, the result is mutable; by the same token, if all arguments are immutable, the result is naturally immutable. But if a procedure is passed both mutable and an immutable arguments of the same type, what should be returned?

  • an immutable object (immutable contagion)
  • a mutable object (mutable contagion)
  • decided case-by-case for each procedure and/or each type

Programmer-written code will be decided by the programmer, so we need to decide only for the standard library. SRFI 135 chose uniform immutable contagion of strings without R7RS-small backward compatibility. SRFI 135x provides for uniform immutable contagion. The relevant procedures are string-replace, string-append, string-concatenate, string-concatenate-reverse, string-join, string-map, string-map-index. The SRFI 1 counterparts would be append, concatenate, zip, map, append-map, map-in-order, filter-map, and the lset-* procedures; the SRFI 133 counterparts would be vector-append, vector-concatenate, vector-append-subvectors, vector-map.

One case I didn't discuss before is that of mutability contagion. R7RS-small backward compat requires that if all arguments are mutable, the result is mutable; by the same token, if all arguments are immutable, the result is naturally immutable. But if a procedure is passed both mutable and an immutable arguments of the same type, what should be returned? * an immutable object (immutable contagion) * a mutable object (mutable contagion) * decided case-by-case for each procedure and/or each type Programmer-written code will be decided by the programmer, so we need to decide only for the standard library. SRFI 135 chose uniform immutable contagion of strings without R7RS-small backward compatibility. [SRFI 135x](https://htmlpreview.github.io/?https://raw.githubusercontent.com/johnwcowan/r7rs-work/master/srfi-135x.html) provides for uniform immutable contagion. The relevant procedures are `string-replace`, `string-append`, `string-concatenate`, `string-concatenate-reverse`, `string-join`, `string-map`, `string-map-index`. The SRFI 1 counterparts would be `append`, `concatenate`, `zip`, `map`, `append-map`, `map-in-order`, `filter-map`, and the `lset-*` procedures; the SRFI 133 counterparts would be `vector-append`, `vector-concatenate`, `vector-append-subvectors`, `vector-map`.
Member
Copy link

By R7RS-small compatibility, there's no choice for procedures like append. At least not if literals coincide with immutable versions of pairs/vectors/strings.

I would also advise against too much of such polymorphism. I doubt it can be implemented efficiently, and by general principles, I think it is better if the behavior of a procedure does not depend too much on the types of its inputs - at least not in a dynamically-typed language.

By R7RS-small compatibility, there's no choice for procedures like `append`. At least not if literals coincide with immutable versions of pairs/vectors/strings. I would also advise against too much of such polymorphism. I doubt it can be implemented efficiently, and by general principles, I think it is better if the behavior of a procedure does not depend too much on the types of its inputs - at least not in a dynamically-typed language.
Author
Owner
Copy link

By R7RS-small compatibility, there's no choice for procedures like append. At least not if literals coincide with immutable versions of pairs/vectors/strings.

Yes, that's a difficulty, which is why SRFI 135x says that literals are mutable strings that you can't mutate. If we are to change them to istrings, then (string-append "foo: ", foo) would return an immmutable string per SRFI 135x, which is obviously undesirable. So we have to double up on everything in the standard library that returns a string.

I would also advise against too much of such polymorphism.

For these types that ship has already sailed: we cannot consistently with R7RS-small demand monomorphic procedures mcar for mpairs and icar for ipairs if literals are ipairs: the bulk of the standard procedures dealing with pairs, vectors, and strings are unavoidably mutability polymorphic in their arguments. The issue here is result polymorphism, where the types of the results depends on the types of the arguments.

I doubt it can be implemented efficiently

Removing run-time polymorphism from dynamic languages is a bog-standard optimization for compilers nowadays. Something like 90% of all polymorphic calls are in fact monomorphic or oligomorphic.

I think it is better if the behavior of a procedure does not depend too much on the types of its inputs - at least not in a dynamically-typed language.

That's mostly true in Scheme (I/O and the numeric tower being the exceptions), but it is an outlier among dynamically typed languages, most of which are heavily polymorphic, even ones as close as CL. I often hear complaints about the relentless monomorphism of R7RS-large and Scheme in general, where the type has to be reiterated constantly: (string-append (substring x 0 3) (string-ref y 4)) specifies the type three times over, where polymorphism would allow it not to be specified at all.

These complaints are an additional reason why I think it is important to solve the problem of generic functions in a satisfying way, so that one can write something like (append+ (slice+ x 0 3) (ref+ y 4)), where trailing + is a convention for generic functions. Of course, the underlying functions are still exposed to the programmer (unlike in most languages) if that extra bit of optimization is actually necessary.

> By R7RS-small compatibility, there's no choice for procedures like `append`. At least not if literals coincide with immutable versions of pairs/vectors/strings. Yes, that's a difficulty, which is why SRFI 135x says that literals are mutable strings that you can't mutate. If we are to change them to istrings, then `(string-append "foo: ", foo)` would return an immmutable string per SRFI 135x, which is obviously undesirable. So we have to double up on everything in the standard library that returns a string. > I would also advise against too much of such polymorphism. For these types that ship has already sailed: we cannot consistently with R7RS-small demand monomorphic procedures `mcar` for mpairs and `icar` for ipairs if literals are ipairs: the bulk of the standard procedures dealing with pairs, vectors, and strings are unavoidably mutability polymorphic in their arguments. The issue here is result polymorphism, where the types of the results depends on the types of the arguments. > I doubt it can be implemented efficiently Removing run-time polymorphism from dynamic languages is a bog-standard optimization for compilers nowadays. Something like 90% of all polymorphic calls are in fact monomorphic or oligomorphic. > I think it is better if the behavior of a procedure does not depend too much on the types of its inputs - at least not in a dynamically-typed language. That's mostly true in Scheme (I/O and the numeric tower being the exceptions), but it is an outlier among dynamically typed languages, most of which are heavily polymorphic, even ones as close as CL. I often hear complaints about the relentless monomorphism of R7RS-large and Scheme in general, where the type has to be reiterated constantly: `(string-append (substring x 0 3) (string-ref y 4))` specifies the type three times over, where polymorphism would allow it not to be specified at all. These complaints are an additional reason why I think it is important to solve the problem of generic functions in a satisfying way, so that one can write something like `(append+ (slice+ x 0 3) (ref+ y 4))`, where trailing `+` is a convention for generic functions. Of course, the underlying functions are still exposed to the programmer (unlike in most languages) if that extra bit of optimization is actually necessary.
Sign in to join this conversation.
No Branch/Tag specified
main
pages
proc-draft
c-trichotomy
global-id-prop-ref
allow-van-tonder-like-expanders
No results found.
Labels
Clear labels
Batteries
Issues for the Batteries volume of the report, providing a standard library
Cleanup
Issues where inconsistencies or other infelicities have arisen
Consent Docket
Items which will be automatically be given a certain resolution if no objection is made by a certain date
Environments
Issues for the Environments volume of the report, providing OS interfaces and similar
Foundations
Issues for the Foundations volume of the report, related to the core language semantics
Macrological Fascicle
Meta
Procedural and organisational issues
Multiple proposals exist
Multiple competing, concrete proposals to resolve this issue exist (whether they are SRFI or still only pre-SRFI)
Pie-in-the-sky ideas
Ideas currently lacking any form of worked-out proposal
Problems without solutions
Problems we *must* solve but haven’t worked out any solution for yet
Procedural Fascicle
Public Comment
Publications
Issues related to the practicalities of making the report available
Question
For information and clarification
R6RS Compatibility
Issue touches on questions of R6RS compatibility
R7RS-small
Issues with the Small language Report
Resolution in draft
A resolution (not necessarily final) is specified in the current draft of the relevant fascicle
Specification exists
Proposals for which a viable, but incomplete specification text exists
SRFI/RnRS spec exists
A SRFI for this proposal exists, or a solution from another RnRS
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
scheme/r7rs#74
Reference in a new issue
scheme/r7rs
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?