As the one who brought up the issue, I feel obliged to come up with a
suggestion to fix, but haven't quite got it yet.  We should discuss the
fundamental semantic difference between functional and linear-updating
versions in the "Linear update" section, and introduce the conversion/copy
procedures.  We may give examples of different implementation strategies
(e.g. all-functional, flagging the object, etc.).


On Sun, Jun 6, 2021 at 7:36 AM Marc Nieper-Wißkirchen <
[email protected]> wrote:

> John, I am not sure whether your analysis hits the nail right on its head.
>
> When we have been talking about persistent vs. transient objects here, we
> haven't meant that this has to be reflected on the Scheme language level.
> In fact, we have been talking about these on the same semantic level as
> SRFI 113 and SRFI 146 already do.
>
> The root cause of our discussion here is about a different thing, that has
> been surfaced thanks to Shiro: With the current semantics, we have it that
> if any of the provided linear update procedures exported by SRFI 113 or
> SRFI 146 do, in fact, modifier its argument, every functional update
> procedure is forced to return a newly allocated structure. This makes
> implementations whose linear update procedures are more than just wrappers
> around the functional ones very inefficient when it comes to the functional
> interface. The current semantics of SRFI 113 or SRFI 146 is just bad; it
> connects two very different things that should have been considered
> separately.
>
> The solution that is proposed by us here is to untangle the dependency of
> the semantics of the functional on the implementation-aspect of the
> linear-update part of the specs. Our solution means to drop the requirement
> that functional update procedures return newly allocated objects. Instead,
> it will be made an error to feed an object returned by a functional update
> procedure into a linear update procedure without copying it first.
>
> When we want to model this in a sufficiently rich static typing system
> (which would be outside the Scheme language), it makes sense to talk about
> transient and persitent versions of the objects. We can optionally get some
> type-safety in Scheme at the runtime level by splitting the copy procedure
> into three versions:
>
> transient->persistent
> persistent->transient
> copy-transient
>
> An implementation could add a flag to each object to remember whether it
> was produced by a functional update procedure and check this flag when the
> above procedures (whose names are just placeholders) are called.
>
> In an implementation that does not want to check the requirements at
> runtime, transient->persistent would be the identity, and the other two the
> same copying procedure.
>
> In a nutshell, the current requirement that newly allocated structures are
> returned will be dropped in exchange for a single procedure that actually
> does have to newly allocate, namely persistent->transient.
>
> -- Marc
>
> Am So., 6. Juni 2021 um 18:56 Uhr schrieb John Cowan <[email protected]>:
>
>>
>>
>> On Sat, Jun 5, 2021 at 8:05 AM Marc Nieper-Wißkirchen <
>> [email protected]> 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.
>>>
>>
>> I haven't been following this thread closely, but it seems to me that the
>> topic has drifted from functional vs. linear-update *procedures* to
>> persistent vs. transient *objects*.  Invoking (foo-swizzle bar) guarantees
>> that bar will not be visibly mutated, whereas invoking (foo-swizzle! bar)
>> makes no such guarantee.   If foo objects are not in fact mutable, these
>> are probably the same procedure.  If foos are in fact mutable, then
>> foo-swizzle probably makes a copy and foo-swizzle! does not.
>>
>> Only in the case where foos can be either immutable or mutable is it
>> necessary to have two types and keep track of what you've got, and provide
>> foo-freeze and foo-thaw to convert between them  And there is an
>> alternative to this, namely the Builder pattern, in which foos and
>> foo-builders have entirely separate APIs: foos are immutable, whereas
>> foo-builders are not, but only support mutation operations and cannot be
>> used as foos.
>>
>> We have generally avoided the Builder pattern in favor of the Constructor
>> pattern, but there are cases (histograms are my favorite one) where
>> mutability is highly desirable, and the Builder pattern might be a win.
>>
>

Reply via email to