I think we can understand the notion of persistent vs. transient values
much like const vs. non-const-qualified types in C made a bit stricter. In
the exposed API, there won't be a type predicate that can distinguish
between persistent and transient values but the implementation can make
this distinction internally to detect violations of the protocol.

In the specifications, we drop the requirements that all returned
structures have to be newly allocated by the functional updaters.

Then some arguments and some values of the exported procedures are denoted
persistent or transient (we have to go through the procedures individually
to make sure we get it right). (If Scheme had a rich static affine type
system, these markings would become type qualifiers.) No value returned is
neither marked persistent nor transient.

Then, we add a clause saying that it is an error to use a value marked
transient as an argument marked persistent and vice versa. It is also an
error to reuse a value marked transient after it has been used as an
argument marked persistent.

Finally, we add three procedures copy, transient->persistent,
persistent->transistent.

An R6RS implementation would report assertion violations in case any of
these requirements are breached.

The names "transient" and "persistent" and the names of the conversion
functions are subject to discussion, of course.

To give some examples for the new signatures (illustrated with SRFI 146):

mapping: <comparator> <object>* -> <transient mapping>
mapping-contains?: <mapping> <object> -> <boolean>
mapping-ref: <mapping> <object> -> <object>
mapping-adjoin: <persistent mapping> <object>* -> <persistent mapping>
mapping-adjoin!: <transient mapping> <object>* -> <transient mapping>
mapping-copy: <mapping> -> <transient mapping>
mapping-persistent->transient: <persistent mapping> -> <transient mapping>
mapping-transient->persistent: <transient mapping> -> <persistent mapping>
alist->mapping: <comparator> <alist> -> <transient mapping>

Note that the constructors return transient mappings. The reason is that
these transient mappings can be cheaply converted to persistent mappings
(by the logical operation transient->persistent, which can be implemented
as a no-op), while the conversion in the other direction involves a copy.

Marc


Am Mo., 7. Juni 2021 um 03:20 Uhr schrieb Wolfgang Corcoran-Mathe <
[email protected]>:

> On 2021-06-05 14:05 +0200, Marc Nieper-Wißkirchen wrote:
> > Wolfgang, what do you think? We should get it right with SRFI 224 first
> > (before it is finalized) and then we can correct SRFI 113 and 146 (am I
> > missing another relevant SRFI) ex post facto.
>
> Marc, thanks to you and Shiro for all of the interesting
> discussion.
>
> I'm not sure I understand the proposed solution, or the exact
> meanings of the terms "persistent" and "transient" in this
> context.  Before changing the semantics of SRFI 224, I'd like to
> make sure I'm clear on what we're suggesting, and how it will
> impact interactions with other Scheme libraries.  Would all
> functional procedures now be specified to return a persistent
> value, while -! forms would be required to take transient
> values?
>
> If I understand correctly, the core of the problem is that the
> expectation that "you, the programmer, know there are no other live
> references to the value passed to the procedure" is unreasonable,
> unless the library provides guarantees or adheres rigidly to the
> (awful) "always copy everything" protocol.  (Please correct that
> if I've misunderstood.)
>
> --
> Wolfgang Corcoran-Mathe  <[email protected]>
>
> "In the military more is not better." --_Sun Tzu_
>

Reply via email to