On Sat, Aug 15, 2020 at 8:11 AM Marc Nieper-Wißkirchen <xxxxxx@nieper-wisskirchen.de> wrote:

Please excuse the belated reply.

No problem at all.  I am juggling many conversations at once.
 
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.)

Using `eval` is never trivial.  Its *theory* is trivial, which is Not a Good Thing.  See Mitchell Wand's classic paper "The Theory of Fexprs Is Trivial" (fexprs are closely related to eval), and/or Albert R. Meyer's "Thirteen Puzzles" paper which it cites (a draft is online at <http://people.csail.mit.edu/meyer/puzzle.pdf>).  (I am aware of John Shutt's able and ingenious special pleading.)

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.

The fact is that they are not doing so.
 
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.

All true, though a little benchmarking wouldn't be amiss.  I suspect the main performance difference would arise from car and cdr being inlined and record accessors not being inlined, something that could profitably be fixed with wide benefits.  In Chicken declarations can be written to provide cross-module inlining of the accessors.

In other words,
implementations have to catch up anyway

They don't, in fact.  The great advantage of SRFI 116 is that it's here now.  It's not ideal, but it provides the facility of fully immutable pairs to programmers in a way that:

o   doesn't require help from the Scheme implementer

o   doesn't depend on implementation-defined behavior

o   works uniformly in all R[67]RS Schemes as it stands (with trivial adjustments)

o   doesn't break Scheme (unlike Racket).

That is a formidable set of advantages which I am unwilling to dismiss lightly.  Indeed, in R6RS the immutability is enforceable against frame-breaking by making the ipair type opaque and sealed.  This may or may not provide performance advantages as well.
 
"Signaling an error" is the wrong phrase here. It has to be
implementation-dependent how the mutation is detected and reported.

Why?
 
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.

It needs to be general; it's reasonable for a program to assume that if ipair? returns #t on an object, then the other i-procedures will work on it too.  A proposal will appear in due course.
 
> 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.

Users are the people who need to see the value of true immutability, and if their favorite Scheme can provide it without bothering implementers to provide it, then it has a better chance of catching on.

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).

Perhaps it isn't.

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.

Or, unfortunately, by simply returning the argument and saying "See, now it's immutable, because that just means it's an error to mutate it!"  While that is even simpler than SRFI 116, it hardly serves the purposes of SRFI 116 in practice.

SRFI 124 is another matter, because the garbage collector is deeply unspecified; indeed, it is not even mentioned in the RnRS standards.  Java nowadays even provides the Epsilon GC (that is, no GC at all) for use by programs that are highly latency sensitive and whose memory allocation is known (e.g. "allocate a big array in advance and that's all"), or for short-running programs which have a sufficient heap and need not bother with the GC at the end of the program (normally done in order to run finalizers).

It would be useful to rewrite the SRFI implementation to call a procedure that returns #t iff its argument is known to the Scheme implementation to be de facto immutable; the default version of this procedure would simply return #f always.



John Cowan          http://vrici.lojban.org/~cowan        xxxxxx@ccil.org
La mayyitan ma qadirun yatabaqqa sarmadi
Fa idha yaji' al-shudhdhadh fa-l-maut qad yantahi.
                --Abdullah al-Hazred, Al-`Azif