emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Unbalanced change hooks (part 2) [Documentation fix still remaining]


From: Davis Herring
Subject: Re: Unbalanced change hooks (part 2) [Documentation fix still remaining]
Date: Thu, 1 Sep 2016 15:25:01 -0600
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.2

This is a naïve interpretation of what a "change" means and entails.
In reality, some changes are done with a single call to an insdel
function, while others need multiple calls that delete and insert text
piecemeal.  Thus the need to call the hooks before and after each
insdel call only sometimes.

Indeed, no one knows what we mean by "change". To make progress, we must introduce a formal definition for it, in particular in conjunction with the word "before" -- preferably a definition that the current implementation satisfies but that allows useful reasoning.

As has been said, some of the proposed documentation that disclaims "pairing" produces a definition that is satisfied but is uselessly vague -- allowing the implementation to simply call b-c-f once with (point-min) and (point-max) when the buffer is created, and never again. (Changes beyond the initial (point-max) are simply insertions into that interval!)

However, we intuitively know that b-c-f is supposed to be called "immediately before" a change; what does that mean? Certainly it is not a statement about the real passage of time or function calls. It has to be based on an ordering of relevant events -- b-c-f calls, a-c-f calls, and the changes themselves. The "properly paired" ideal defines "immediately before" as "with no change intervening" (and similarly for a-c-f), disallowing the implementation from reporting what Dan calls "fine-grained" changes only via a-c-f.

We can offer a weaker (but still useful) formal guarantee that the current implementation does satisfy phrased instead in terms of _absence_ of change: a call to a-c-f "publishes" an interval of text where changes have been completed and which shall not be altered until after a subsequent b-c-f call that "unlocks" it. (These intervals act like rear-advancing overlays: a zero-length interval must be unlocked to allow an insertion, and an a-c-f call that covers an unlocked interval entirely destroys it without any zero-length remainder.) Lack of alteration is easier to define than change (because it is a state function, not a path function), and it is what all caching clients rely on for the validity of their caches.

There remains a gap in the information provided by this guarantee (and the current implementation): when no a-c-f region corresponds exactly to a preceding b-c-f call, clients are left to wonder whether more changes may yet occur. At the least, we must publish all text before redisplay (to prevent the user from observing text not yet processed by a-c-f), but we can leave redisplay out of it by having each function which currently makes "unpaired" calls do one of several things when it exits:

1. Make an additional call to a-c-f that covers the whole region (which, in this interpretation, is not a violation because a-c-f is a promise not to modify in the future rather than a statement about modifications in the past). This destroys the utility of the smaller a-c-f regions, of course.

2. Call some new hook to indicate that the remaining unlocked text has been republished in its original state. (Note that it does not matter if the text was actually changed and then changed back, so long as all text properties and markers were restored and no other hooks were called.)

3. Make another call to b-c-f and a-c-f with, say, (point-max) (point-max). We would then document that each call to b-c-f (for a buffer) indicates that any text not covered by a-c-f since the last b-c-f is republished unaltered. This fits the current implementation and the intuitive idea that b-c-f is called before "each" change because it separates changes into epochs demarcated by b-c-f.

I therefore propose approach #3 as the minimal change to the current implementation that provides a behavioral guarantee worth documenting. Moreover, the demarcation of changes into epochs allows interested clients to work with the "paired" behavior by deferring a-c-f operations until the next b-c-f or precisely matching a-c-f. (If all functions follow #3, then either the first a-c-f matches or the sequence will be terminated by a b-c-f.)

Davis

--
This product is sold by volume, not by mass. If it appears too dense or too sparse, it is because mass-energy conversion has occurred during shipping.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]