Subject: bug#76313: New function `replace-region`

From: Stefan Monnier <[email-masked]>
Date: Sun, 30 Mar 2025 11:30:18 -0400

>> > I'd prefer a completely backward-compatible change of passing a
>> > special value of MAX-SECS to indicate that the potentially costly
>> > algorithm is to be bypassed.
>> We already have that: pass a 0 for MAX-SECS.
> So we should probably mention this in the documentation?

I think that's already implied by the doc of MAX-SECS:

    The MAX-SECS argument, if given, defines a hard limit on the time used
    for comparing the buffers.  If it takes longer than MAX-SECS, the
    function falls back to a plain ‘delete-region’ and
    ‘insert-buffer-substring’.  (Note that the checks are not performed
    too evenly over time, so in some cases it may run a bit longer than
    allowed).

>> IOW, if you have code that uses
>> 
>>     (replace-region-contents BEG END SOURCE 0)
>> 
>> and you change it to:
>> 
>>     (replace-region-contents BEG END SOURCE 0.1)
>> 
>> thinking "oh, I can afford to spend a bit more time here, let's
>> enable the fancy diff algorithm", you may end up breaking your code.
>
> So maybe these subtleties should be described in the manual?  And if
> the caller doesn't care, or has point in a place that won't bump into
> these issues, then replace-region-contents can still be used as a Lisp
> API to replace_region?

I feel like this is setting up a trap for the average coder.

> For example, a loop like you describe above could carefully place
> point before each call to re-search-forward, to avoid the
> problems, no?

Of course, the careful coder will find a solution.

I still can't understand why you're so opposed to having
2 different functions.

In comparison, we have:

On the insertion side:
  - insert
  - insert-and-inherit
  - insert-before-markers
  - insert-buffer-substring
  - insert-buffer
  - insert-into-buffer
On the deletion side:
  - delete-region
  - delete-char
  - delete-and-extract-region
  - erase-buffer

I mean, I understand that the above functions all cover somewhat
different calling cases [side note: `replace-region-contents` tries to
unify them], whereas `replace-region` and `replace-region-carefully`
would be called with the same arguments to "do the same".

But I don't think coders would have any difficulty understanding that
one of them is the low-level, deterministic, O(N) primitive while the
other is a "smart" O(almost N²) alternative, with a much larger constant
factor, which decomposes the replacement into smaller calls to
`replace-region`, using heuristics, with the uncertainty this entails.

        Stefan