Re: either-guard reference implementation Marc Nieper-WiÃkirchen 15 Aug 2020 12:11 UTC
Please excuse the belated reply. Am Di., 11. Aug. 2020 um 18:48 Uhr schrieb John Cowan <email@example.com>: >> Standard pair procedures already accept immutable pairs in the form of >> datum literals. > > > Literal pairs, as I will call them (as distinct from ordinary pairs and ipairs), are immutable only in the sense that it is an error to mutate them. However, implementations *may* allow their routine mutation: Cyclone, Chibi, Sagittarius, Kawa, STklos, Scheme48, Loko, T prevent mutation, MIT, Gambit, Chicken, Guile, IronScheme, Bigloo, Loko, Gauche, Chez, Mosh, Larceny, Vicare, Picrin, Schemik, TinyScheme permit it. Furthermore, it is impossible to create one at run time or detect one. Indeed, the idea would be to allow the creation of such "literal pairs" at runtime easily. (NB: It's not true that they cannot be created by any means at runtime; through a trivial use of 'eval' it is possible.) That "it is an error" to mutate them should be enough. This helps adoption and Schemes can start to add modes, in which such mutations are detected. > That means that they do not serve the purposes of ipairs, that of guaranteeing (modulo frame-breaking implementation extensions) that they cannot be mutated by buggy code. Ipairs are, I claim, easier to reason about and easier to use in many situations, particularly extreme ones, than either ordinary pairs or literal pairs. No existing code uses ipairs. And I guess the amount of code that has been written since SRFI 116 and uses ipairs is neglecable. Moreover, unless implementations special-case ipairs natively, ordinary pairs and literal pairs are most likely more performant. In other words, implementations have to catch up anyway, but then it makes more sense to invest this energy into making literal pairs truly immutable. > If all systems signaled an error on an attempt to mutate a literal pair, then indeed an `icons` analogue that returned a literal pair would suffice. But they don't and it's my belief that they won't. So if you want the advantages of immutability, you have to pay the cost of incompatible behavior. "Signaling an error" is the wrong phrase here. It has to be implementation-dependent how the mutation is detected and reported. > I will, however, request another PFN for 116 that strikes out the claim that ordinary-pair operations should not support ipairs, and addis a recommendation for them to do so (nothing stronger is portable). This is not a matter of subtyping but of ad hoc polymorphism, as in SRFI 135 procedures that accept textuals. That sounds like a good idea for sure. In any case, "ipair?" has to be allowed to return #t when applied to a literal pair. >> Just drop "ipair?" from SRFI 116 and the route to >> adoption is easy. > > > That is as much as to say "Drop SRFI 116 altogether", since it will no longer serve any purpose to write icar rather than car. Not at all; "icar" would return an immutable pair, which is relevant for implementations that check whether they are mutated. >> From a risk-mitigation viewpoint, you won't choose an implementation >> that is silent on "(car 0)" either. We can expect that most quality >> implementations will detect the error once they have found time to >> adopt immutable strings, vectors and pairs. > > > We cannot expect them to do the latter: see above. If implementers see the value of true immutability, they will improve their implementations in this regard. I think it is comparable to the situation of SRFI 124. > >> >> The good thing with this >> approach is that all existing code will still work. > > > I don't understand this claim. Mutable pairs are not going away (except in Racket), so of course existing code will still work. I mean the you if you have legacy code operating on pairs and that this legacy claims not to mutate the pairs, you can easily feed it with the immutable pairs of my proposal (which doesn't seem to be much different to your idea of a new PFN). Marc PS Somewhere on the SRFI 116 mailing list, I think I have proposed procedures like the following: (immutable OBJ) and (immutable! OBJ) The first procedure creates an immutable copy of OBJ (whether a pair, a string, vector, record, ...). It may reuse OBJ if it is already immutable. The second procedure is a linear-update variant of the former. These procedures could be implemented either by extension of the tagging system or by copying the data to heap areas that are mprotected against writing and relying on SIGSEGV.