all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
@ 2022-09-29  5:29 Gerd Möllmann
  2022-09-29  6:28 ` Eli Zaretskii
                   ` (2 more replies)
  0 siblings, 3 replies; 68+ messages in thread
From: Gerd Möllmann @ 2022-09-29  5:29 UTC (permalink / raw)
  To: 58158

In its current form, interval tree iteration works like this:

1. Call begin_iteration(T) to iterate over tree T
2. do stuff
3. Call end_iteration(T)

with the following rules:

- Begin_iteration and end_iteration must be paired.

- There can be only one iteration per tree at a time.  Nested iteration
  over the same tree is not supported (abort).

- No GC may happen in step 2.  This is because mark_buffer iterates over
  buffer overlays.

I think this is an exceedingly dangerous design.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29  5:29 bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful Gerd Möllmann
@ 2022-09-29  6:28 ` Eli Zaretskii
  2022-09-29  7:03   ` Gerd Möllmann
  2022-10-06 22:26 ` Matt Armstrong
  2023-10-06 13:14 ` Gerd Möllmann
  2 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-09-29  6:28 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 58158

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Date: Thu, 29 Sep 2022 07:29:25 +0200
> 
> In its current form, interval tree iteration works like this:
> 
> 1. Call begin_iteration(T) to iterate over tree T
> 2. do stuff
> 3. Call end_iteration(T)
> 
> with the following rules:
> 
> - Begin_iteration and end_iteration must be paired.
> 
> - There can be only one iteration per tree at a time.  Nested iteration
>   over the same tree is not supported (abort).
> 
> - No GC may happen in step 2.  This is because mark_buffer iterates over
>   buffer overlays.
> 
> I think this is an exceedingly dangerous design.

Why, because of "no GC" requirement?  We could ensure that by calling
inhibit_garbage_collection (if the code doesn't do that already).
That is not very elegant, and might even cause memory pressure in some
(hopefully rare) situations, but we do have some users of this in the
sources.

What higher-level operations require "interval tree iteration" that
you describe?  Which primitives end up doing such iterations?





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29  6:28 ` Eli Zaretskii
@ 2022-09-29  7:03   ` Gerd Möllmann
  2022-09-29  8:08     ` Eli Zaretskii
  0 siblings, 1 reply; 68+ messages in thread
From: Gerd Möllmann @ 2022-09-29  7:03 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 58158

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Gerd Möllmann <gerd.moellmann@gmail.com>
>> Date: Thu, 29 Sep 2022 07:29:25 +0200
>> 
>> In its current form, interval tree iteration works like this:
>> 
>> 1. Call begin_iteration(T) to iterate over tree T
>> 2. do stuff
>> 3. Call end_iteration(T)
>> 
>> with the following rules:
>> 
>> - Begin_iteration and end_iteration must be paired.
>> 
>> - There can be only one iteration per tree at a time.  Nested iteration
>>   over the same tree is not supported (abort).
>> 
>> - No GC may happen in step 2.  This is because mark_buffer iterates over
>>   buffer overlays.
>> 
>> I think this is an exceedingly dangerous design.
>
> Why, because of "no GC" requirement?  We could ensure that by calling
> inhibit_garbage_collection (if the code doesn't do that already).

It doesn't.

BTW, if anything signals in step 2, so that end_iteration isn't called,
we're also hosed.

> What higher-level operations require "interval tree iteration" that
> you describe?  Which primitives end up doing such iterations?

What has to do with overlays.  To name a few: overlay-at, overlays-in,
next-overlay-change, previous-overlay-change, overlay-lists, ...

I personally think this is a no-go.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29  7:03   ` Gerd Möllmann
@ 2022-09-29  8:08     ` Eli Zaretskii
  2022-09-29  9:09       ` Gerd Möllmann
  0 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-09-29  8:08 UTC (permalink / raw)
  To: Gerd Möllmann, Stefan Monnier; +Cc: 58158

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: 58158@debbugs.gnu.org
> Date: Thu, 29 Sep 2022 09:03:17 +0200
> 
> >> - No GC may happen in step 2.  This is because mark_buffer iterates over
> >>   buffer overlays.
> >> 
> >> I think this is an exceedingly dangerous design.
> >
> > Why, because of "no GC" requirement?  We could ensure that by calling
> > inhibit_garbage_collection (if the code doesn't do that already).
> 
> It doesn't.

Should be easy to fix, no?

> BTW, if anything signals in step 2, so that end_iteration isn't called,
> we're also hosed.

record_unwind_protect should fix that, right?
(inhibit_garbage_collection already employs this mechanism).

> > What higher-level operations require "interval tree iteration" that
> > you describe?  Which primitives end up doing such iterations?
> 
> What has to do with overlays.  To name a few: overlay-at, overlays-in,
> next-overlay-change, previous-overlay-change, overlay-lists, ...
> 
> I personally think this is a no-go.

Really?  Even if we take all the measures mentioned above?  Why so?





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29  8:08     ` Eli Zaretskii
@ 2022-09-29  9:09       ` Gerd Möllmann
  2022-09-29  9:37         ` Eli Zaretskii
  2022-10-01  1:57         ` Richard Stallman
  0 siblings, 2 replies; 68+ messages in thread
From: Gerd Möllmann @ 2022-09-29  9:09 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 58158, Stefan Monnier

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Gerd Möllmann <gerd.moellmann@gmail.com>
>> I personally think this is a no-go.
>
> Really?  Even if we take all the measures mentioned above?

Yes.

> Why so?

I think it simply can't be that what is basically walking a binary tree
requires such restrictions.  And if it does because of some quirk of the
interval tree in itree.c, something is seriously wrong with the design.

That's a bit harsh, but I mean it :-).






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29  9:09       ` Gerd Möllmann
@ 2022-09-29  9:37         ` Eli Zaretskii
  2022-09-29 10:05           ` Gerd Möllmann
  2022-10-01  1:57         ` Richard Stallman
  1 sibling, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-09-29  9:37 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 58158, monnier

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: Stefan Monnier <monnier@iro.umontreal.ca>,  58158@debbugs.gnu.org
> Date: Thu, 29 Sep 2022 11:09:17 +0200
> 
> I think it simply can't be that what is basically walking a binary tree
> requires such restrictions.  And if it does because of some quirk of the
> interval tree in itree.c, something is seriously wrong with the design.
> 
> That's a bit harsh, but I mean it :-).

Fair enough.

Can you propose a fix?

I guess the begin_iteration/end_iteration dance is because the tree
could be in inconsistent state in-between?  If so, what would it take
to avoid the inconsistency?





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29  9:37         ` Eli Zaretskii
@ 2022-09-29 10:05           ` Gerd Möllmann
  2022-09-29 10:43             ` Eli Zaretskii
  0 siblings, 1 reply; 68+ messages in thread
From: Gerd Möllmann @ 2022-09-29 10:05 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 58158, monnier

Eli Zaretskii <eliz@gnu.org> writes:

> Can you propose a fix?

Other than completely rewrite at least this part, no.

> I guess the begin_iteration/end_iteration dance is because the tree
> could be in inconsistent state in-between?  If so, what would it take
> to avoid the inconsistency?

I find it very hard to tell why this is done the way it is.  If someone
knowing the code can think of a reason, please speak up.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29 10:05           ` Gerd Möllmann
@ 2022-09-29 10:43             ` Eli Zaretskii
  2022-09-29 11:33               ` Gerd Möllmann
  2022-09-29 13:10               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 68+ messages in thread
From: Eli Zaretskii @ 2022-09-29 10:43 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 58158, monnier

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: monnier@iro.umontreal.ca,  58158@debbugs.gnu.org
> Date: Thu, 29 Sep 2022 12:05:50 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Can you propose a fix?
> 
> Other than completely rewrite at least this part, no.
> 
> > I guess the begin_iteration/end_iteration dance is because the tree
> > could be in inconsistent state in-between?  If so, what would it take
> > to avoid the inconsistency?
> 
> I find it very hard to tell why this is done the way it is.  If someone
> knowing the code can think of a reason, please speak up.

I may be missing something, but it looks like the sole purpose of the
iter_start/iter_finish dance is to ensure only one iteration per tree
is running at any given time, and that's because the iteration uses
some state variable(s) of which there's only one instance per tree.

Stefan, am I missing something?





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29 10:43             ` Eli Zaretskii
@ 2022-09-29 11:33               ` Gerd Möllmann
  2022-09-29 13:10               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 68+ messages in thread
From: Gerd Möllmann @ 2022-09-29 11:33 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 58158, monnier

Eli Zaretskii <eliz@gnu.org> writes:

>> I find it very hard to tell why this is done the way it is.  If someone
>> knowing the code can think of a reason, please speak up.
>
> I may be missing something, but it looks like the sole purpose of the
> iter_start/iter_finish dance is to ensure only one iteration per tree
> is running at any given time, and that's because the iteration uses
> some state variable(s) of which there's only one instance per tree.

BTW, It currently uses a "visited" flag in tree nodes, which is kind of
such a state, but something like that is normally not needed when
walking an rb-tree.






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29 10:43             ` Eli Zaretskii
  2022-09-29 11:33               ` Gerd Möllmann
@ 2022-09-29 13:10               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-09-29 13:23                 ` Eli Zaretskii
                                   ` (2 more replies)
  1 sibling, 3 replies; 68+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-09-29 13:10 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Gerd Möllmann, 58158

> I may be missing something, but it looks like the sole purpose of the
> iter_start/iter_finish dance is to ensure only one iteration per tree
> is running at any given time, and that's because the iteration uses
> some state variable(s) of which there's only one instance per tree.
>
> Stefan, am I missing something?

One reason is that traversing a binary tree usually requires something
like recursion, but that wouldn't fit very conveniently with the current
code (nor with C in general since you can't make a local recursive
closure which accesses local variables from the surrounding function).

Another is the need to update the begin/end fields (these need updating
because of insertions/deletions but they're updated lazily while
traversing the tree to avoid an O(N) complexity during the
insertions/deletions).  Hiding that behind 'some kind of "next node"
function keeps the code more readable.

But yes, the current restriction to have a single iteration at a time is
a bit of a problem, especially because it's very "global".  I added
a comment yesterday describing how we could make it non-global (hence
getting rid of the `visited` flag in the nodes).

For now, I pushed a simple fix to traverse the tree "by hand" in the GC
rather than via the iterator.


        Stefan






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29 13:10               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-09-29 13:23                 ` Eli Zaretskii
  2022-09-29 16:48                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-09-29 13:40                 ` Eli Zaretskii
  2022-09-29 14:15                 ` Gerd Möllmann
  2 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-09-29 13:23 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: gerd.moellmann, 58158

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Gerd Möllmann <gerd.moellmann@gmail.com>,
>   58158@debbugs.gnu.org
> Date: Thu, 29 Sep 2022 09:10:19 -0400
> 
> > I may be missing something, but it looks like the sole purpose of the
> > iter_start/iter_finish dance is to ensure only one iteration per tree
> > is running at any given time, and that's because the iteration uses
> > some state variable(s) of which there's only one instance per tree.
> >
> > Stefan, am I missing something?
> 
> One reason is that traversing a binary tree usually requires something
> like recursion, but that wouldn't fit very conveniently with the current
> code (nor with C in general since you can't make a local recursive
> closure which accesses local variables from the surrounding function).

I'm not sure I understand how recursion is related.  Are you saying
that recursion is replaced with iteration?  But then, if _start and
_finish are called by the same caller, we don't really need the
protection, since no one can start another iteration while the first
one runs.  Right?

> Another is the need to update the begin/end fields (these need updating
> because of insertions/deletions but they're updated lazily while
> traversing the tree to avoid an O(N) complexity during the
> insertions/deletions).  Hiding that behind 'some kind of "next node"
> function keeps the code more readable.

Where in the code do you see iteration that adds or deletes nodes?

> For now, I pushed a simple fix to traverse the tree "by hand" in the GC
> rather than via the iterator.

So this removes the restriction of not having GC during iteration?

Also, I take it that you don't consider the current code is as
"harmful" as Gerd thinks it is?  IOW, you don't share his opinion that
this implementation is a "no-go"?





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29 13:10               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-09-29 13:23                 ` Eli Zaretskii
@ 2022-09-29 13:40                 ` Eli Zaretskii
  2022-09-29 14:15                 ` Gerd Möllmann
  2 siblings, 0 replies; 68+ messages in thread
From: Eli Zaretskii @ 2022-09-29 13:40 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: gerd.moellmann, 58158

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Gerd Möllmann <gerd.moellmann@gmail.com>,
>   58158@debbugs.gnu.org
> Date: Thu, 29 Sep 2022 09:10:19 -0400
> 
> Another is the need to update the begin/end fields (these need updating
> because of insertions/deletions but they're updated lazily while
> traversing the tree to avoid an O(N) complexity during the
> insertions/deletions).  Hiding that behind 'some kind of "next node"
> function keeps the code more readable.

Btw, couldn't we handle this by having a flag in the node that tells
us whether the begin/end fields can be trusted?  Then the first caller
who need them would run the update and reset the flags, and we still
have lazy update, albeit somewhat less lazy, but without the need for
guarding the iteration with start/finish calls.  Would that work?





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29 13:10               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-09-29 13:23                 ` Eli Zaretskii
  2022-09-29 13:40                 ` Eli Zaretskii
@ 2022-09-29 14:15                 ` Gerd Möllmann
  2022-09-29 14:37                   ` Gerd Möllmann
  2022-09-29 16:40                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2 siblings, 2 replies; 68+ messages in thread
From: Gerd Möllmann @ 2022-09-29 14:15 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, 58158

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> One reason is that traversing a binary tree usually requires something
> like recursion, but that wouldn't fit very conveniently with the current
> code (nor with C in general since you can't make a local recursive
> closure which accesses local variables from the surrounding function).

Ok, usually, but not necessarily.  The alternative is to implement an
iterator that starts with a node N, and an implementation of a successor
function, which return the successor of N in a given order.  This
requires a parent pointer in nodes, but that we have.

(Something like this is used for ordered containers like "map" and "set"
in C++ STL, for instance, which are based on rb-trees in GCC's
libstdc++.)

> Another is the need to update the begin/end fields (these need updating
> because of insertions/deletions but they're updated lazily while
> traversing the tree to avoid an O(N) complexity during the
> insertions/deletions).  Hiding that behind 'some kind of "next node"
> function keeps the code more readable.

Is this for buffer text changes, something akin to a delayed update of
marker positions?  I already wondered where that was.

> But yes, the current restriction to have a single iteration at a time is
> a bit of a problem, especially because it's very "global".  I added
> a comment yesterday describing how we could make it non-global (hence
> getting rid of the `visited` flag in the nodes).

BTW, and related to iteration directly, did you notice this in
interval_tree_insert?

      /* This suggests that nodes in the right subtree are strictly
         greater.  But this is not true due to later rotations. */
      child = node->begin <= child->begin ? child->left : child->right;





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29 14:15                 ` Gerd Möllmann
@ 2022-09-29 14:37                   ` Gerd Möllmann
  2022-09-29 22:09                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-09-29 16:40                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 68+ messages in thread
From: Gerd Möllmann @ 2022-09-29 14:37 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, 58158

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Stefan Monnier <monnier@iro.umontreal.ca> writes:
>
>> One reason is that traversing a binary tree usually requires something
>> like recursion, but that wouldn't fit very conveniently with the current
>> code (nor with C in general since you can't make a local recursive
>> closure which accesses local variables from the surrounding function).
>
> Ok, usually, but not necessarily.  The alternative is to implement an
> iterator that starts with a node N, and an implementation of a successor
> function, which return the successor of N in a given order.  This
> requires a parent pointer in nodes, but that we have.
>
> (Something like this is used for ordered containers like "map" and "set"
> in C++ STL, for instance, which are based on rb-trees in GCC's
> libstdc++.)

The code from libstdc++ is this (from libstdc++-v3/src/c++98/tree.cc):

  static _Rb_tree_node_base*
  local_Rb_tree_increment(_Rb_tree_node_base* __x) throw ()
  {
    if (__x->_M_right != 0)
      {
        __x = __x->_M_right;
        while (__x->_M_left != 0)
          __x = __x->_M_left;
      }
    else
      {
        _Rb_tree_node_base* __y = __x->_M_parent;
        while (__x == __y->_M_right)
          {
            __x = __y;
            __y = __y->_M_parent;
          }
        if (__x->_M_right != __y)
          __x = __y;
      }
    return __x;
  }

I hope one can read that.

The idea is to find the root of the smallest subtree containing the
current node, and proceed from there.  That's why the parent pointer is
needed.

Symmmetrical for max->min ordering.  And finding min/max is trivial.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29 14:15                 ` Gerd Möllmann
  2022-09-29 14:37                   ` Gerd Möllmann
@ 2022-09-29 16:40                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 68+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-09-29 16:40 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, 58158

Gerd Möllmann [2022-09-29 16:15:09] wrote:
> Stefan Monnier <monnier@iro.umontreal.ca> writes:
>> One reason is that traversing a binary tree usually requires something
>> like recursion, but that wouldn't fit very conveniently with the current
>> code (nor with C in general since you can't make a local recursive
>> closure which accesses local variables from the surrounding function).
> Ok, usually, but not necessarily.  The alternative is to implement an
> iterator that starts with a node N, and an implementation of a successor
> function, which return the successor of N in a given order.

The approach currently used is somewhat similar to that.  Some of the
difference is that we need an actual "iterator/generator" object to
remember the parameter of the filtering we want to apply to the set of
objects.  And the problem is that this "object" is currently implemented
not only as a global value (thus restricting us to one-iteration at
a time) but also with some parts of the data stored in the tree.
I think this is the part that really needs to be changed.

> This requires a parent pointer in nodes, but that we have.
>
> (Something like this is used for ordered containers like "map" and "set"
> in C++ STL, for instance, which are based on rb-trees in GCC's
> libstdc++.)

Another difference is that itree.c's iterator uses a local "work stack"
instead of traversing the tree exclusively via left/right/parent like in
the code you show.  I don't know if that difference is important, tho.

>> Another is the need to update the begin/end fields (these need updating
>> because of insertions/deletions but they're updated lazily while
>> traversing the tree to avoid an O(N) complexity during the
>> insertions/deletions).  Hiding that behind 'some kind of "next node"
>> function keeps the code more readable.
>
> Is this for buffer text changes, something akin to a delayed update of
> marker positions?

Yes, exactly.

>> But yes, the current restriction to have a single iteration at a time is
>> a bit of a problem, especially because it's very "global".  I added
>> a comment yesterday describing how we could make it non-global (hence
>> getting rid of the `visited` flag in the nodes).
>
> BTW, and related to iteration directly, did you notice this in
> interval_tree_insert?
>
>       /* This suggests that nodes in the right subtree are strictly
>          greater.  But this is not true due to later rotations. */
>       child = node->begin <= child->begin ? child->left : child->right;

No, I had not noticed that yet, and I don't understand this comment.


        Stefan






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29 13:23                 ` Eli Zaretskii
@ 2022-09-29 16:48                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 68+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-09-29 16:48 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gerd.moellmann, 58158

>> > I may be missing something, but it looks like the sole purpose of the
>> > iter_start/iter_finish dance is to ensure only one iteration per tree
>> > is running at any given time, and that's because the iteration uses
>> > some state variable(s) of which there's only one instance per tree.
>> >
>> > Stefan, am I missing something?
>> 
>> One reason is that traversing a binary tree usually requires something
>> like recursion, but that wouldn't fit very conveniently with the current
>> code (nor with C in general since you can't make a local recursive
>> closure which accesses local variables from the surrounding function).
>
> I'm not sure I understand how recursion is related.  Are you saying
> that recursion is replaced with iteration?  But then, if _start and
> _finish are called by the same caller, we don't really need the
> protection, since no one can start another iteration while the first
> one runs.  Right?

Typically, current code will look something like:

    int x;
    Lisp_Object y;

    buffer_overlay_iter_start (current_buffer, prev, pos, ITREE_DESCENDING);
    while ((node = buffer_overlay_iter_next (current_buffer)))
      {
        ... do something that updates x and y ...
      }
    buffer_overlay_iter_finish (current_buffer);

If we were to use recursion, then we'd need to define a new (recursive)
function which does what's currently done in the `while` loop, but this
function can't access `x` and `y`, so it would need to take them as
argument, or a reference to them...

The use of an iterator is definitely convenient (and is a standard
approach in many languages).

>> Another is the need to update the begin/end fields (these need updating
>> because of insertions/deletions but they're updated lazily while
>> traversing the tree to avoid an O(N) complexity during the
>> insertions/deletions).  Hiding that behind 'some kind of "next node"
>> function keeps the code more readable.
>
> Where in the code do you see iteration that adds or deletes nodes?

No, I meant insertion/deletion of text in the buffer, thus requiring
updates to `begin/end` fields.

> Btw, couldn't we handle this by having a flag in the node that tells
> us whether the begin/end fields can be trusted?  Then the first caller
> who need them would run the update and reset the flags, and we still
> have lazy update, albeit somewhat less lazy, but without the need for
> guarding the iteration with start/finish calls.  Would that work?

Yes, it would, but it's still O(N).
The current approach is inspired by the approach used in `intervals.c`
which also updates those fields lazily/ondemand so as to avoid the O(N)
performance impact.

>> For now, I pushed a simple fix to traverse the tree "by hand" in the GC
>> rather than via the iterator.
> So this removes the restriction of not having GC during iteration?

Yes.

> Also, I take it that you don't consider the current code is as
> "harmful" as Gerd thinks it is?

I don't like the global state it uses, but I think we can fix this
aspect without too much trouble.

> IOW, you don't share his opinion that this implementation is
> a "no-go"?

No, indeed, I don't.


        Stefan






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29 14:37                   ` Gerd Möllmann
@ 2022-09-29 22:09                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-09-30  5:28                       ` Gerd Möllmann
  0 siblings, 1 reply; 68+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-09-29 22:09 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, 58158

>   static _Rb_tree_node_base*
>   local_Rb_tree_increment(_Rb_tree_node_base* __x) throw ()
>   {
>     if (__x->_M_right != 0)
>       {
>         __x = __x->_M_right;
>         while (__x->_M_left != 0)
>           __x = __x->_M_left;
>       }
>     else
>       {
>         _Rb_tree_node_base* __y = __x->_M_parent;
>         while (__x == __y->_M_right)
>           {
>             __x = __y;
>             __y = __y->_M_parent;
>           }
>         if (__x->_M_right != __y)
>           __x = __y;
>       }
>     return __x;
>   }
>
> I hope one can read that.

I changed the code to store the `visited` bit in the work stack, but if
you could rewrite the `interval_generator_next` along the lines of the
code above that would be great.
[ An alternative would be to try and get rid of the `parent` field :-)  ]


        Stefan






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29 22:09                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-09-30  5:28                       ` Gerd Möllmann
  2022-09-30  6:11                         ` Eli Zaretskii
  2022-09-30 13:25                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 68+ messages in thread
From: Gerd Möllmann @ 2022-09-30  5:28 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, 58158

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> I changed the code to store the `visited` bit in the work stack, but if
> you could rewrite the `interval_generator_next` along the lines of the
> code above that would be great.

Ok, I'll rewrite that :-).  When I understand what that "narrowing" is
and how and for what it is used.

BTW, what do you think of changing function names to something a bit
shorter?  I find myself constantly getting confused when reading the
code.  I think an "itree_" prefix would suffice for non-static
functions, and static ones without prefix.  Renaming that is hopefully
not that much work with LSP.

> [ An alternative would be to try and get rid of the `parent` field :-)
> ]

:-)





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-30  5:28                       ` Gerd Möllmann
@ 2022-09-30  6:11                         ` Eli Zaretskii
  2022-09-30 11:31                           ` Gerd Möllmann
  2022-10-06 22:36                           ` Dmitry Gutov
  2022-09-30 13:25                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 2 replies; 68+ messages in thread
From: Eli Zaretskii @ 2022-09-30  6:11 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 58158, monnier

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: Eli Zaretskii <eliz@gnu.org>,  58158@debbugs.gnu.org
> Date: Fri, 30 Sep 2022 07:28:26 +0200
> 
> Renaming that is hopefully not that much work with LSP.

You should be able to do this with M-? followed by
"M-x xref-query-replace-in-results RET" (the latter
should be invoked in the "*xref*" buffer produced by M-?).





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-30  6:11                         ` Eli Zaretskii
@ 2022-09-30 11:31                           ` Gerd Möllmann
  2022-09-30 18:29                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-10-06 22:36                           ` Dmitry Gutov
  1 sibling, 1 reply; 68+ messages in thread
From: Gerd Möllmann @ 2022-09-30 11:31 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 58158, monnier

On 22-09-30 8:11 , Eli Zaretskii wrote:
>> From: Gerd Möllmann <gerd.moellmann@gmail.com>
>> Cc: Eli Zaretskii <eliz@gnu.org>,  58158@debbugs.gnu.org
>> Date: Fri, 30 Sep 2022 07:28:26 +0200
>>
>> Renaming that is hopefully not that much work with LSP.
> 
> You should be able to do this with M-? followed by
> "M-x xref-query-replace-in-results RET" (the latter
> should be invoked in the "*xref*" buffer produced by M-?).

Ok, thanks for the tip.

Info for Stefan: I've now removed the per-tree null node, and make check 
shows no unexpected results.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-30  5:28                       ` Gerd Möllmann
  2022-09-30  6:11                         ` Eli Zaretskii
@ 2022-09-30 13:25                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-09-30 14:08                           ` Gerd Möllmann
  1 sibling, 1 reply; 68+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-09-30 13:25 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, 58158

Gerd Möllmann [2022-09-30 07:28:26] wrote:
> Stefan Monnier <monnier@iro.umontreal.ca> writes:
>> I changed the code to store the `visited` bit in the work stack, but if
>> you could rewrite the `interval_generator_next` along the lines of the
>> code above that would be great.
> Ok, I'll rewrite that :-).  When I understand what that "narrowing" is
> and how and for what it is used.

The traversals are always bound by begin..end boundaries.  Usually we
know those bounds upfront (e.g. for `overlays-in` or `overlay-at`), but
when doing things like `next/previous-overlay-change` one of the bounds
is not know at first, so in order to try and avoid the O(N) complexity
the code refines that other bound on the fly (e.g. when searching
forward, after seeing an overlay that ends at POS we know that there's no
point looking further than POS so we can move the end boundary to POS).

> BTW, what do you think of changing function names to something a bit
> shorter?  I find myself constantly getting confused when reading the
> code.  I think an "itree_" prefix would suffice for non-static
> functions, and static ones without prefix.

Fine by me, yes.


        Stefan






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-30 13:25                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-09-30 14:08                           ` Gerd Möllmann
  2022-09-30 15:25                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 68+ messages in thread
From: Gerd Möllmann @ 2022-09-30 14:08 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, 58158

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> The traversals are always bound by begin..end boundaries.  Usually we
> know those bounds upfront (e.g. for `overlays-in` or `overlay-at`), but
> when doing things like `next/previous-overlay-change` one of the bounds
> is not know at first, so in order to try and avoid the O(N) complexity
> the code refines that other bound on the fly (e.g. when searching
> forward, after seeing an overlay that ends at POS we know that there's no
> point looking further than POS so we can move the end boundary to
> POS).

Thanks, that helps.

Maybe you could also help me with the questions below?

I'm assuming, from a comment somewhere, that an interval tree is an
rb-tree with keys being interval start positions, and allowing
duplicates.

That is, if N is a node, all nodes in the subtree N->left are strictly <
N, and nodes in N->right are >=.  Or in a picture, if [start, end] is an
interval, and we insert some intervals with the same start, we could
arrive at

                 [5, a]
                /      \
            [4, b]     [6, c]
              /\         /  \
             0  0       0   [6, d]
                              /\
                              ...

where 0 means null, and 6 is a duplicate start.

1. Is that correct?

2. Does the tree order duplicates in a particular way?  Maybe by overlay
priority, or by interval end?  And, perhaps, if it doesn't order
duplicates, would it be an idea to order them, maybe at some later
point?  I'm asking this because a successor(N) function would return
nodes in the order in the tree, always, and I don't know what the order
is now.

3. If my mental picture is right, we could of course end up with a tree
that has degenerated to a list.  Or a subtree, maybe.  Do you know if
that can happen?






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-30 14:08                           ` Gerd Möllmann
@ 2022-09-30 15:25                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-09-30 16:04                               ` Eli Zaretskii
                                                 ` (2 more replies)
  0 siblings, 3 replies; 68+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-09-30 15:25 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, Andreas Politz, 58158

> Maybe you could also help me with the questions below?

I'll try (BTW, the original author is Andreas Politz who we can still
reach at <mail@andreas-politz.de>.  He doesn't have much time to devote
to it, tho, so best not to Cc him through all the conversations).

> I'm assuming, from a comment somewhere, that an interval tree is an
> rb-tree with keys being interval start positions, and allowing
> duplicates.

Yup.

> That is, if N is a node, all nodes in the subtree N->left are strictly <
> N, and nodes in N->right are >=.

The following code in `interval_tree_insert`:

  while (child != ITREE_NULL)
    {
      parent = child;
      offset += child->offset;
      child->limit = max (child->limit, node->end - offset);
      /* This suggests that nodes in the right subtree are strictly
         greater.  But this is not true due to later rotations. */
      child = node->begin <= child->begin ? child->left : child->right;
    }

suggests that N->left are <= and N->right are > but my reading of the
comment is that the only thing we can rely on is that N-<left is <= and
N->right is >=

[ I do understand this comment now :-)  ]

> 2. Does the tree order duplicates in a particular way?
> Maybe by overlay priority, or by interval end?

AFAICT, no it does not.

> And, perhaps, if it doesn't order duplicates, would it be an idea to
> order them, maybe at some later point?  I'm asking this because
> a successor(N) function would return nodes in the order in the tree,
> always, and I don't know what the order is now.

Ordering based on interval end could arguably make sense.  I'm not
completely sure how/where it would benefit us, tho.  Most times we look
at the itree, we just look at *all* the nodes within a specific
interval, so the order in which they're returned doesn't matter very
much (the ordering within the tree does matter in terms of how we manage
to prune the tree, but that has more to do with which elements are near
the root, which is a different kind of "ordering" than the "binary tree
ordering" itself).  Maybe the `next/previous-overlay-change` code
benefit from sub-ordering based on `end`, but I suspect the effect would
be lost in the noise: if we want to speed up that part of the code,
I expect that a better avenue is to rewrite the
`next/previous-single-overlay-change` so as not to work by (while ..
(next/previous-overlay-change ..) .. (get-char-property ..) ..) where
both functions do the O(log N) itree-iteration dance, but instead doing
the itree iteration itself.

> 3. If my mental picture is right, we could of course end up with a tree
> that has degenerated to a list.  Or a subtree, maybe.  Do you know if
> that can happen?

In terms of tree depth, no: the code preserves the RB invariants, which
ensure balance regardless of ordering (or lack thereof).


        Stefan






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-30 15:25                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-09-30 16:04                               ` Eli Zaretskii
  2022-09-30 17:11                                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-10-01  5:06                               ` Gerd Möllmann
  2022-10-01  7:25                               ` Gerd Möllmann
  2 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-09-30 16:04 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: gerd.moellmann, mail, 58158

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Eli Zaretskii <eliz@gnu.org>,  58158@debbugs.gnu.org, Andreas Politz
>  <mail@andreas-politz.de>
> Date: Fri, 30 Sep 2022 11:25:30 -0400
> 
> > And, perhaps, if it doesn't order duplicates, would it be an idea to
> > order them, maybe at some later point?  I'm asking this because
> > a successor(N) function would return nodes in the order in the tree,
> > always, and I don't know what the order is now.
> 
> Ordering based on interval end could arguably make sense.  I'm not
> completely sure how/where it would benefit us, tho.  Most times we look
> at the itree, we just look at *all* the nodes within a specific
> interval, so the order in which they're returned doesn't matter very
> much (the ordering within the tree does matter in terms of how we manage
> to prune the tree, but that has more to do with which elements are near
> the root, which is a different kind of "ordering" than the "binary tree
> ordering" itself).  Maybe the `next/previous-overlay-change` code
> benefit from sub-ordering based on `end`, but I suspect the effect would
> be lost in the noise: if we want to speed up that part of the code,
> I expect that a better avenue is to rewrite the
> `next/previous-single-overlay-change` so as not to work by (while ..
> (next/previous-overlay-change ..) .. (get-char-property ..) ..) where
> both functions do the O(log N) itree-iteration dance, but instead doing
> the itree iteration itself.

The display engine sorts the overlays, so order could be important.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-30 16:04                               ` Eli Zaretskii
@ 2022-09-30 17:11                                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 68+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-09-30 17:11 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gerd.moellmann, mail, 58158

>> Ordering based on interval end could arguably make sense.  I'm not
>> completely sure how/where it would benefit us, tho.  Most times we look
>> at the itree, we just look at *all* the nodes within a specific
>> interval, so the order in which they're returned doesn't matter very
>> much (the ordering within the tree does matter in terms of how we manage
>> to prune the tree, but that has more to do with which elements are near
>> the root, which is a different kind of "ordering" than the "binary tree
>> ordering" itself).  Maybe the `next/previous-overlay-change` code
>> benefit from sub-ordering based on `end`, but I suspect the effect would
>> be lost in the noise: if we want to speed up that part of the code,
>> I expect that a better avenue is to rewrite the
>> `next/previous-single-overlay-change` so as not to work by (while ..
>> (next/previous-overlay-change ..) .. (get-char-property ..) ..) where
>> both functions do the O(log N) itree-iteration dance, but instead doing
>> the itree iteration itself.
>
> The display engine sorts the overlays, so order could be important.

Indeed, for things like `overlays_at` it would be handy if the iterator
could return the right overlays already in the right order, so we don't
have to `sort_overlays`.

But in `sort_overlays` the `priority` property takes precedence, so if
we order the RB tree based on that ordering, we will lose the main
purpose of the change, i.e. finding the overlays at POS in O(log N)
time, because the `compare_overlays` ordering does not let us know that
all of the left or right subtree is outside of a given interval.
IOW the itree has to use a different ordering than that of
`compare_overlays` anyway, so we're still forced to (re-)sort afterwards
with `sort_overlays` :-(


	Stefan






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-30 11:31                           ` Gerd Möllmann
@ 2022-09-30 18:29                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-10-02  8:06                               ` Gerd Möllmann
  0 siblings, 1 reply; 68+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-09-30 18:29 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, 58158

> Info for Stefan: I've now removed the per-tree null node, and make check
> shows no unexpected results.

Thanks.  It's an improvement, but I still don't understand how it
works :-(


        Stefan






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29  9:09       ` Gerd Möllmann
  2022-09-29  9:37         ` Eli Zaretskii
@ 2022-10-01  1:57         ` Richard Stallman
  2022-10-01  7:00           ` Eli Zaretskii
  1 sibling, 1 reply; 68+ messages in thread
From: Richard Stallman @ 2022-10-01  1:57 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eliz, 58158, monnier

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > I think it simply can't be that what is basically walking a binary tree
  > requires such restrictions.

If we allow running complicated code during the tree walk, that would
be asking for trouble.  But if the operations done during the tree
walk are simple and written in C, it should be clear that there is no
possibility of this kind of a bug.  Isn't that the case?

  > > What has to do with overlays.  To name a few: overlay-at, overlays-in,
  > > next-overlay-change, previous-overlay-change, overlay-lists, ...

Those operations can be done in C with no risk of signaling an error.

That ought to be sufficient, as long as we don't need the code to be
reentrant.  If the code needs to be reentrant then we would have
to eliminate the "visited" flag.  But if we don't run Lisp code
during the tree-walk, we should not need it to be reentrant.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-30 15:25                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-09-30 16:04                               ` Eli Zaretskii
@ 2022-10-01  5:06                               ` Gerd Möllmann
  2022-10-01 13:54                                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-10-01  7:25                               ` Gerd Möllmann
  2 siblings, 1 reply; 68+ messages in thread
From: Gerd Möllmann @ 2022-10-01  5:06 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, Andreas Politz, 58158

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> That is, if N is a node, all nodes in the subtree N->left are strictly <
>> N, and nodes in N->right are >=.
>
> The following code in `interval_tree_insert`:
>
>   while (child != ITREE_NULL)
>     {
>       parent = child;
>       offset += child->offset;
>       child->limit = max (child->limit, node->end - offset);
>       /* This suggests that nodes in the right subtree are strictly
>          greater.  But this is not true due to later rotations. */
>       child = node->begin <= child->begin ? child->left : child->right;
>     }
>
> suggests that N->left are <= and N->right are > but my reading of the
> comment is that the only thing we can rely on is that N-<left is <= and
> N->right is >=

Phew.  I'm not sure but I get the feeling that makes implementing a
successor function, let's say, challenging.

I wonder how std::multimap deals with that.  Hm.

Anyways, with your removal of the visited flag (N thumbs up, for large
values of N :-)), most of the problems I preceived are gone anyway.
So, I guess we can live with the iteration stack, which seems to work
fine, and the alternative is only nice to have, now.

(And impacts are getting closer in the real world here, so I'm
a bit distracted anyway.)

>
> [ I do understand this comment now :-)  ]

:-)

>
>> 2. Does the tree order duplicates in a particular way?
>> Maybe by overlay priority, or by interval end?
>
> AFAICT, no it does not.

Ok.

>> And, perhaps, if it doesn't order duplicates, would it be an idea to
>> order them, maybe at some later point?  I'm asking this because
>> a successor(N) function would return nodes in the order in the tree,
>> always, and I don't know what the order is now.
>
> Ordering based on interval end could arguably make sense.  I'm not
> completely sure how/where it would benefit us, tho.  Most times we look
> at the itree, we just look at *all* the nodes within a specific
> interval, so the order in which they're returned doesn't matter very
> much (the ordering within the tree does matter in terms of how we manage
> to prune the tree, but that has more to do with which elements are near
> the root, which is a different kind of "ordering" than the "binary tree
> ordering" itself).  Maybe the `next/previous-overlay-change` code
> benefit from sub-ordering based on `end`, but I suspect the effect would
> be lost in the noise: if we want to speed up that part of the code,
> I expect that a better avenue is to rewrite the
> `next/previous-single-overlay-change` so as not to work by (while ..
> (next/previous-overlay-change ..) .. (get-char-property ..) ..) where
> both functions do the O(log N) itree-iteration dance, but instead doing
> the itree iteration itself.

Thanks.

>
>> 3. If my mental picture is right, we could of course end up with a tree
>> that has degenerated to a list.  Or a subtree, maybe.  Do you know if
>> that can happen?
>
> In terms of tree depth, no: the code preserves the RB invariants, which
> ensure balance regardless of ordering (or lack thereof).

Ok, thanks for your insights!





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-01  1:57         ` Richard Stallman
@ 2022-10-01  7:00           ` Eli Zaretskii
  0 siblings, 0 replies; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-01  7:00 UTC (permalink / raw)
  To: rms; +Cc: gerd.moellmann, 58158, monnier

> From: Richard Stallman <rms@gnu.org>
> Cc: eliz@gnu.org, 58158@debbugs.gnu.org, monnier@iro.umontreal.ca
> Date: Fri, 30 Sep 2022 21:57:36 -0400
> 
>   > > What has to do with overlays.  To name a few: overlay-at, overlays-in,
>   > > next-overlay-change, previous-overlay-change, overlay-lists, ...
> 
> Those operations can be done in C with no risk of signaling an error.

I think such assumptions were proven dangerous at best in the long
run.  The way Emacs develops, we constantly add more and more hooks to
C code, and more and more direct calls into Lisp from C.  These
invalidate any assumptions about "no risk of signaling an error", even
if they were originally true when the code was first written.

Moreover, we test for QUIT in operations that can be prolonged ones
(and for a good reason), so any long loop in C could potentially throw
to top level if the user pressed C-g.

All in all, experience shows that making such assumptions in Emacs is
unsafe.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-30 15:25                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-09-30 16:04                               ` Eli Zaretskii
  2022-10-01  5:06                               ` Gerd Möllmann
@ 2022-10-01  7:25                               ` Gerd Möllmann
  2022-10-01 10:55                                 ` Gerd Möllmann
  2022-10-01 14:01                                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2 siblings, 2 replies; 68+ messages in thread
From: Gerd Möllmann @ 2022-10-01  7:25 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, Andreas Politz, 58158

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Maybe you could also help me with the questions below?
>
> I'll try (BTW, the original author is Andreas Politz who we can still
> reach at <mail@andreas-politz.de>.  He doesn't have much time to devote
> to it, tho, so best not to Cc him through all the conversations).
>
>> I'm assuming, from a comment somewhere, that an interval tree is an
>> rb-tree with keys being interval start positions, and allowing
>> duplicates.
>
> Yup.
>
>> That is, if N is a node, all nodes in the subtree N->left are strictly <
>> N, and nodes in N->right are >=.
>
> The following code in `interval_tree_insert`:
>
>   while (child != ITREE_NULL)
>     {
>       parent = child;
>       offset += child->offset;
>       child->limit = max (child->limit, node->end - offset);
>       /* This suggests that nodes in the right subtree are strictly
>          greater.  But this is not true due to later rotations. */
>       child = node->begin <= child->begin ? child->left : child->right;
>     }
>
> suggests that N->left are <= and N->right are > but my reading of the
> comment is that the only thing we can rely on is that N-<left is <= and
> N->right is >=
>

Yup.  I've used overlay-tree a bit (compile with ITREE_DEBUG defined
after pulling), and used this:

(defun make-ivs ()
  (with-current-buffer (get-buffer-create "*iv*")
    (delete-all-overlays)
    (erase-buffer)
    (insert (make-string 50 ?x))
    (let ((o1 (make-overlay 1 1))
	  (o2 (make-overlay 10 11))
	  (o3 (make-overlay 10 12))
	  (o4 (make-overlay 1 1))
	  )
      (move-overlay o4 10 13)
      (overlay-tree))))

(pp (make-ivs))
((:begin 10 :end 12 :limit 13 :offset 0 :rear-advance nil :front-advance nil)
 ((:begin 1 :end 1 :limit 13 :offset 0 :rear-advance nil :front-advance nil)
  nil
  ((:begin 10 :end 13 :limit 13 :offset 0 :rear-advance nil :front-advance nil)
   nil nil))
 ((:begin 10 :end 11 :limit 11 :offset 0 :rear-advance nil :front-advance nil)
  nil nil))

That's 

                    [10, 12]
                   /        \
                 [1, 1]      [10, 11]
                 /    \         /\
                    [10, 13]
                     /    \
                          
The 10 is found "all over the place".

I surmise no reasonable successor function can be written for such a
tree.

I have to look at std::multimap, they manage to do this somehow.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-01  7:25                               ` Gerd Möllmann
@ 2022-10-01 10:55                                 ` Gerd Möllmann
  2022-10-01 14:01                                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 68+ messages in thread
From: Gerd Möllmann @ 2022-10-01 10:55 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, Andreas Politz, 58158

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> I have to look at std::multimap, they manage to do this somehow.

Well, I should have thought of that, because it's obvious from the fact
they are able to use successor/predecessor functions :-/.

The equivalent in our code would go like below, which is just written
down in a hurry, so please bear with me.  It's just about the idea.  So:

Insert a new interval_node only if overlay start is not in the tree
already.  If the contains a node for the start, make the node's value a
list of overlays, and add the new one to it in an order that's
convenient (The STL uses insertion order).


As a consequence, keys is the rb-tree are unique, and it is always
strictly ordered, rotations don't change that.  The min node is the
left-most node in a tree, and so on.

So far so good.


An iterator in the order min->max would have to record the interval_node
in the tree plus information where in the list of overlays it is, if it
is in any.  Finding the next node is implemented with a successor
function like the one I've shown from libstdc++.

To find all overlays containing a given position POS, find the node
whose start is <= POS.  Start at the root of the tree, and walk the left
link until we find the ndoes's start is <= POS.  Then iterate forward
until start > POS, returning only overlapping overlays.

Finding overlays intersecting an interval [BEG, END] is not as nice, but
we can exclude intervals starting after END.  So we have to iterate over
all overlays from the minimum of the tree, and iterate forward until we
reach the first excluded one.

That's so "easy" that even I can understand how it works :-).

What am I overlooking?





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-01  5:06                               ` Gerd Möllmann
@ 2022-10-01 13:54                                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-10-02  8:22                                   ` Gerd Möllmann
  0 siblings, 1 reply; 68+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-10-01 13:54 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, Andreas Politz, 58158

>> The following code in `interval_tree_insert`:
[...]
>> suggests that N->left are <= and N->right are > but my reading of the
>> comment is that the only thing we can rely on is that N-<left is <= and
>> N->right is >=
>
> Phew.  I'm not sure but I get the feeling that makes implementing a
> successor function, let's say, challenging.

I don't think it makes any difference in that respect, no.  The notion of
"successor" is just "the successor in the in-order traversal of the
tree" and while rotations change the initial property that "N->right are >",
they don't change the in-order traversal output (they don't re-order
nodes w.r.t in-order traversal (or in reverse order for that matter)).

As alluded to at the end of my previous email, while RB trees are
typically used for your usual binary tree which comes with some notion
of ordering that makes lookup O(log N), the RB trees ensure balance
without relying on any notion of ordering since the rotations just
blindly preserve the order as a side effect but they don't themselves
need to call the ordering function to decide how to do their job.


        Stefan






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-01  7:25                               ` Gerd Möllmann
  2022-10-01 10:55                                 ` Gerd Möllmann
@ 2022-10-01 14:01                                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 68+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-10-01 14:01 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, Andreas Politz, 58158

> That's 
>
>                     [10, 12]
>                    /        \
>                  [1, 1]      [10, 11]
>                  /    \         /\
>                     [10, 13]
>                      /    \
>                           
> The 10 is found "all over the place".

"all over the place" if you consider the pre-order or post-order
traversal, indeed.  But if you look at the in-order traversal (e.g., the
one you'd get from C++ `local_Rb_tree_increment` you showed), you get
the expected result:

   [1, 1]
   [10, 13]
   [10, 12]
   [10, 11]


-- Stefan






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-30 18:29                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-10-02  8:06                               ` Gerd Möllmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Möllmann @ 2022-10-02  8:06 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, 58158

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Info for Stefan: I've now removed the per-tree null node, and make check
>> shows no unexpected results.
>
> Thanks.  It's an improvement, but I still don't understand how it
> works :-(

Is it still null->parent?

If so, maybe it helps to picture that null is a child of many parents
:-).  Every node having null on the left or right is a parent in that
sense.  Therefore, if some code uses null->parent to do something it can
not be right.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-01 13:54                                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-10-02  8:22                                   ` Gerd Möllmann
  2022-10-02 16:32                                     ` Andreas Politz
  0 siblings, 1 reply; 68+ messages in thread
From: Gerd Möllmann @ 2022-10-02  8:22 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, Andreas Politz, 58158

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Phew.  I'm not sure but I get the feeling that makes implementing a
>> successor function, let's say, challenging.
>
> I don't think it makes any difference in that respect, no.

The reason I find it challenging, and I'm sure now, is that I've written
the following code, and failed :-).

/* FIXME: This assumption is wrong.  Nodes on the left of P are <=,
   and nodes on the right are >=.  */

/* Value is the successor of interval node X in ascending order.  It
   is assumed that the tree is organized so that nodes < X are in
   X->left and nodes in X->right are >= X.  */

static struct interval_node *
in_order_successor (struct interval_node *x)
{
  if (x->right != ITREE_NULL)
    {
      /* X has a right child, which means X's right subtree has
	 elements >= X.  Proceed to the left-most child in the right
	 subtree, which is the smallest in that subtree.  */
      x = x->right;
      while (x->left != 0)
	x = x->left;
    }
  else
    {
      /* X's left subtree is uninteresting, because everything there
	 is < X.  Therefore follow the parent chain.  If X is the
	 parent's right child, this means the parent is < X,  We are
	 looking for a parent that is >=.  */
      struct interval_node *y = x->parent;
      while (x == y->right)
	{
	  x = y;
	  y = y->parent;
	}

      /* If we found a parent that's >=, the parent is what we sought.
	 Otherwise, X has arrived at the null node, whose right child
	 is the sentinel node itself.  */
      if (x->right != y)
	x = y;
    }

  return x;
}

I tried to change the comments and/or modify the code for a tree like we
have (left subtree <=, right >=), and couldn't explain why it works,
but I also couldn't produce a counter-example that the existing tree
code actually can produce.  IOW, I couldn't prove anything.

P.S.

With the "all over the place" I indented to hint at the fact that the
tree is not a "normal" BST.  I should probably have said that directly,
sorry.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-02  8:22                                   ` Gerd Möllmann
@ 2022-10-02 16:32                                     ` Andreas Politz
  2022-10-03  4:35                                       ` Gerd Möllmann
  0 siblings, 1 reply; 68+ messages in thread
From: Andreas Politz @ 2022-10-02 16:32 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, 58158, Stefan Monnier

[-- Attachment #1: Type: text/plain, Size: 450 bytes --]

I've managed to construct a prototype of this "stateless" iterator.

I've only implemented the in-order case and only applied it in the overlays_in function.

The only real trouble I had was with pushing the offset to the children
during the tree navigation in some kind of sensible way.  In the end I
gave up and simply pasted calls to the corresponding function "all over
the place".  It seems to work, at least buffer-tests are passing.

Andreas


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: noverlay-stateless-iterator.diff --]
[-- Type: text/x-patch, Size: 6871 bytes --]

diff --git a/src/buffer.c b/src/buffer.c
index f59fddcbde..6a53b49aad 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2948,15 +2948,16 @@ overlays_in (ptrdiff_t beg, ptrdiff_t end, bool extend,
   ptrdiff_t next = ZV;
   Lisp_Object *vec = *vec_ptr;
   struct interval_node *node;
+  struct interval_tree_iterator iterator;
 
-  ITREE_FOREACH (node, current_buffer->overlays, beg,
-                 /* Find empty OV at Z ? */
-                 (end >= ZV && empty) ? ZV + 1 : ZV, ASCENDING)
+  interval_tree_iterator_init(&iterator, current_buffer->overlays, beg,
+			      (end >= ZV && empty) ? ZV + 1 : ZV, ITREE_ASCENDING);
+
+  while ((node = interval_tree_iterator_next(&iterator)))
     {
       if (node->begin > end)
         {
           next = min (next, node->begin);
-          ITREE_FOREACH_ABORT ();
           break;
         }
       else if (node->begin == end)
@@ -2964,7 +2965,6 @@ overlays_in (ptrdiff_t beg, ptrdiff_t end, bool extend,
           next = node->begin;
           if ((! empty || end < ZV) && beg < end)
             {
-              ITREE_FOREACH_ABORT ();
               break;
             }
         }
diff --git a/src/itree.c b/src/itree.c
index eeecaf1839..21549fe8a7 100644
--- a/src/itree.c
+++ b/src/itree.c
@@ -1190,3 +1190,132 @@ interval_tree_subtree_min (const struct interval_tree *tree, struct interval_nod
  * +===================================================================================+ */
 
 /* See Foverlay_tree in buffer.c */
+
+\f
+/* +===================================================================================+
+ * | Stateless iterator
+ * +===================================================================================+ */
+
+static bool
+interval_tree_iter_traverse_p(struct interval_tree_iterator *iterator,
+                              struct interval_node *node);
+static
+struct interval_node *
+interval_tree_iterator_in_order_successor (struct interval_tree_iterator* iterator);
+
+void
+interval_tree_iterator_init(struct interval_tree_iterator *iterator,
+                            struct interval_tree *tree,
+                            ptrdiff_t begin,
+                            ptrdiff_t end,
+                            enum interval_tree_order order) {
+  iterator->tree = tree;
+  iterator->node = tree && begin <= end ? ITREE_NULL : NULL;
+  iterator->begin = begin;
+  iterator->end = end;
+  iterator->order = order;
+}
+
+struct interval_node *
+interval_tree_iterator_next(struct interval_tree_iterator *iterator) {
+  if (iterator->node) {
+    do {
+      switch (iterator->order) {
+      case ITREE_ASCENDING:
+        iterator->node = interval_tree_iterator_in_order_successor (iterator);
+        break;
+      default:
+        fprintf (stderr, "interval_tree_order != ITREE_ASCENDING not implemented");
+        emacs_abort ();
+      }
+    } while (iterator->node &&
+             ! interval_node_intersects (iterator->node, iterator->begin, iterator->end));
+  }
+
+  if (iterator->node == ITREE_NULL) {
+    fprintf (stderr, "Next node: ITREE_NULL\n");
+  } else if (! iterator->node) {
+    fprintf (stderr, "Next node: NULL\n");
+  } else {
+    fprintf (stderr, "Next node: begin = %ld, end = %ld (iterator: begin = %ld, end = %ld)\n",
+             iterator->node->begin, iterator->node->end, iterator->begin, iterator->end);
+  }
+  return iterator->node;
+}
+
+static bool
+interval_tree_iter_traverse_p(struct interval_tree_iterator *iterator,
+                              struct interval_node *node) {
+  eassert (node);
+
+  if (node == ITREE_NULL) {
+    return false;
+  } else {
+    eassert (node->parent != ITREE_NULL);
+    if (node->parent->left == node) {
+      return iterator->begin <= node->limit + node->offset;
+    } else {
+      return node->parent->begin <= iterator->end;
+    }
+  }
+}
+
+static
+struct interval_node *
+interval_tree_iterator_in_order_successor (struct interval_tree_iterator* iterator)
+{
+  struct interval_node *node = iterator->node;
+
+  if (node != ITREE_NULL) {
+    interval_tree_inherit_offset (iterator->tree, node);
+  }
+
+  if (node == ITREE_NULL) {
+    node = iterator->tree->root;
+    if (node != ITREE_NULL) {
+      interval_tree_inherit_offset (iterator->tree, node);
+    }
+    while (interval_tree_iter_traverse_p(iterator, node->left)) {
+      node = node->left;
+      if (node != ITREE_NULL) {
+        interval_tree_inherit_offset (iterator->tree, node);
+      }
+    }
+  } else if (interval_tree_iter_traverse_p(iterator, node->right))
+    {
+      node = node->right;
+      if (node != ITREE_NULL) {
+        interval_tree_inherit_offset (iterator->tree, node);
+      }
+      while (interval_tree_iter_traverse_p(iterator, node->left)) {
+        node = node->left;
+        if (node != ITREE_NULL) {
+          interval_tree_inherit_offset (iterator->tree, node);
+        }
+      }
+    }
+  else
+    {
+      struct interval_node *parent = node->parent;
+      while (node == parent->right)
+        {
+          node = parent;
+          parent = parent->parent;
+        }
+      if (node != ITREE_NULL)
+        node = parent;
+    }
+
+  return node == ITREE_NULL ? NULL : node;
+}
+
+void
+interval_tree_iterator_narrow (struct interval_tree_iterator *iterator,
+                               ptrdiff_t begin,
+                               ptrdiff_t end)
+{
+  eassert (begin >= iterator->begin);
+  eassert (end <= iterator->end);
+  iterator->begin =  max (begin, iterator->begin);
+  iterator->end =  min (end, iterator->end);
+}
diff --git a/src/itree.h b/src/itree.h
index 1f019a2607..53f03cca35 100644
--- a/src/itree.h
+++ b/src/itree.h
@@ -72,6 +72,15 @@ #define ITREE_NULL (&itree_null)
   ITREE_PRE_ORDER,
 };
 
+struct interval_tree_iterator
+{
+  struct interval_tree *tree;
+  struct interval_node *node;
+  ptrdiff_t begin;
+  ptrdiff_t end;
+  enum interval_tree_order order;
+};
+
 void interval_node_init (struct interval_node *, ptrdiff_t, ptrdiff_t, bool, bool, Lisp_Object);
 ptrdiff_t interval_node_begin (struct interval_tree *, struct interval_node *);
 ptrdiff_t interval_node_end (struct interval_tree *, struct interval_node *);
@@ -135,4 +144,15 @@ #define ITREE_FOREACH_ABORT() \
 #define ITREE_FOREACH_NARROW(beg, end) \
   interval_generator_narrow (itree_iter_, beg, end)
 
+void interval_tree_nodes (struct interval_tree *tree, struct interval_node **nodes, enum interval_tree_order order);
+
+void interval_tree_iterator_init(struct interval_tree_iterator *iterator,
+				 struct interval_tree *tree,
+				 ptrdiff_t begin,
+				 ptrdiff_t end,
+				 enum interval_tree_order order);
+struct interval_node *interval_tree_iterator_next(struct interval_tree_iterator *iterator);
+void interval_tree_iterator_narrow (struct interval_tree_iterator *iterator,
+			       ptrdiff_t begin,
+			       ptrdiff_t end);
 #endif

^ permalink raw reply related	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-02 16:32                                     ` Andreas Politz
@ 2022-10-03  4:35                                       ` Gerd Möllmann
  2022-10-04 10:50                                         ` Andreas Politz
  0 siblings, 1 reply; 68+ messages in thread
From: Gerd Möllmann @ 2022-10-03  4:35 UTC (permalink / raw)
  To: Andreas Politz; +Cc: Eli Zaretskii, 58158, Stefan Monnier

Andreas Politz <mail@andreas-politz.de> writes:

> It seems to work, at least buffer-tests are passing.

"seems to work" is a bit weak.  Can we prove it?

I don't mean mathematically, but by reasoning like I tried in the
comments in successor function I posted,





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-03  4:35                                       ` Gerd Möllmann
@ 2022-10-04 10:50                                         ` Andreas Politz
  0 siblings, 0 replies; 68+ messages in thread
From: Andreas Politz @ 2022-10-04 10:50 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, 58158, Stefan Monnier

My implementation seems to work. The correctness of the algorithm would follow from 

1. The Rb tree algorithm produces a tree with left <= root <= right,
2. the algorithm you’ve posted, and I’ve  adapted, produces an in–order of the tree and
3. the conditions guiding the traversal are correct, i.e. they don’t exclude matching intervals.

Since I believe these statements are true, I believe the algorithm is correct.

Andreas



> Am 03.10.2022 um 06:35 schrieb Gerd Möllmann <gerd.moellmann@gmail.com>:
> 
> Andreas Politz <mail@andreas-politz.de> writes:
> 
>> It seems to work, at least buffer-tests are passing.
> 
> "seems to work" is a bit weak.  Can we prove it?
> 
> I don't mean mathematically, but by reasoning like I tried in the
> comments in successor function I posted,






^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29  5:29 bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful Gerd Möllmann
  2022-09-29  6:28 ` Eli Zaretskii
@ 2022-10-06 22:26 ` Matt Armstrong
  2023-10-06 13:14 ` Gerd Möllmann
  2 siblings, 0 replies; 68+ messages in thread
From: Matt Armstrong @ 2022-10-06 22:26 UTC (permalink / raw)
  To: Andreas Politz, Gerd Möllmann; +Cc: Eli Zaretskii, 58158, Stefan Monnier

Andreas Politz <mail@andreas-politz.de> writes:

> I've managed to construct a prototype of this "stateless" iterator.
>
> I've only implemented the in-order case and only applied it in the overlays_in function.
>
> The only real trouble I had was with pushing the offset to the children
> during the tree navigation in some kind of sensible way.  In the end I
> gave up and simply pasted calls to the corresponding function "all over
> the place".  It seems to work, at least buffer-tests are passing.

Hey Andreas, this looks pretty good to me but I have some questions on
it.


> +static
> +struct interval_node *
> +interval_tree_iterator_in_order_successor (struct interval_tree_iterator* iterator)
> +{
> +  struct interval_node *node = iterator->node;
> +
> +  if (node != ITREE_NULL) {
> +    interval_tree_inherit_offset (iterator->tree, node);
> +  }
> +  if (node == ITREE_NULL) {
> +    node = iterator->tree->root;

I don't understand this branch.  If the node is NULL upon entry to the
successor call, why start at the root?  Why is the "next in order node"
of NULL the root?  The root is just an node whose BEG is roughly in the
middle of the total inorder traversal, right?

The "stateless" inorder traversal algorithm I am used to starts with the
minimum node (walk only left links down from the root until at a leaf
and that is the minimum).  Then do inorder traversal from there.


> +    if (node != ITREE_NULL) {
> +      interval_tree_inherit_offset (iterator->tree, node);
> +    }
> +    while (interval_tree_iter_traverse_p(iterator, node->left)) {
> +      node = node->left;
> +      interval_tree_inherit_offset (iterator->tree, node);
> +    }
> +  } else if (interval_tree_iter_traverse_p(iterator, node->right))
> +    {
> +      node = node->right;
> +      interval_tree_inherit_offset (iterator->tree, node);
> +      while (interval_tree_iter_traverse_p(iterator, node->left)) {
> +        node = node->left;
> +        interval_tree_inherit_offset (iterator->tree, node);
> +      }
> +    }
> +  else
> +    {
> +      struct interval_node *parent = node->parent;
> +      while (node == parent->right)
> +        {
> +          node = parent;
> +          parent = parent->parent;
> +        }
> +      if (node != ITREE_NULL)
> +        node = parent;
> +    }
> +
> +  return node == ITREE_NULL ? NULL : node;
> +}

I don't understand how the last "else" case works correctly in the face
of a call to `interval_generator_narrow` during iteration.  Narrowing
could render a node's parent out of the "interesting" range, and so the
iterator should not return it but instead keep trying to find a
successor in range.  Right?





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-30  6:11                         ` Eli Zaretskii
  2022-09-30 11:31                           ` Gerd Möllmann
@ 2022-10-06 22:36                           ` Dmitry Gutov
  2022-10-07 19:47                             ` Eli Zaretskii
  1 sibling, 1 reply; 68+ messages in thread
From: Dmitry Gutov @ 2022-10-06 22:36 UTC (permalink / raw)
  To: Eli Zaretskii, Gerd Möllmann; +Cc: 58158, monnier

On 30.09.2022 09:11, Eli Zaretskii wrote:
> "M-x xref-query-replace-in-results RET"

JFYI this command has the convenient binding 'r' in Xref output buffers.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-06 22:36                           ` Dmitry Gutov
@ 2022-10-07 19:47                             ` Eli Zaretskii
  2022-10-08 18:50                               ` Dmitry Gutov
  0 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-07 19:47 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: gerd.moellmann, 58158, monnier

> Date: Fri, 7 Oct 2022 01:36:17 +0300
> Cc: 58158@debbugs.gnu.org, monnier@iro.umontreal.ca
> From: Dmitry Gutov <dgutov@yandex.ru>
> 
> On 30.09.2022 09:11, Eli Zaretskii wrote:
> > "M-x xref-query-replace-in-results RET"
> 
> JFYI this command has the convenient binding 'r' in Xref output buffers.

It also works only when invoked from the Xref buffer, right?

Btw, what am I doing wrong below?

 emacs -Q
 C-x C-f src/character.h RET
 M-x visit-tags-table RET RET
 M-. char_string RET
 r whatever RET

Unexpected result: "No suitable matches here".  Huh? what did I miss?





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-07 19:47                             ` Eli Zaretskii
@ 2022-10-08 18:50                               ` Dmitry Gutov
  2022-10-10  8:10                                 ` Eli Zaretskii
  0 siblings, 1 reply; 68+ messages in thread
From: Dmitry Gutov @ 2022-10-08 18:50 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gerd.moellmann, 58158, monnier

On 07.10.2022 22:47, Eli Zaretskii wrote:
>> Date: Fri, 7 Oct 2022 01:36:17 +0300
>> Cc: 58158@debbugs.gnu.org, monnier@iro.umontreal.ca
>> From: Dmitry Gutov <dgutov@yandex.ru>
>>
>> On 30.09.2022 09:11, Eli Zaretskii wrote:
>>> "M-x xref-query-replace-in-results RET"
>>
>> JFYI this command has the convenient binding 'r' in Xref output buffers.
> 
> It also works only when invoked from the Xref buffer, right?

Yep.

But we also have commands like xref-find-references-and-replace and 
dired-do-find-regexp-and-replace.

> Btw, what am I doing wrong below?
> 
>   emacs -Q
>   C-x C-f src/character.h RET
>   M-x visit-tags-table RET RET
>   M-. char_string RET
>   r whatever RET
> 
> Unexpected result: "No suitable matches here".  Huh? what did I miss?

We can't replace over "find definition" matches: they are more abstract 
and don't contain the necessary information to perform the replacement 
(such as the length of a match, for instance).

And such xrefs might navigate you to the beginning of the line, for 
example, rather than to the beginning of the name.

But that makes sense, doesn't it? If replacing over "find definitions" 
results worked fine, in the end you would get a codebase where all 
declarations of a method 'foo' got renamed, but all callsites of it 
remain unchanged. That couldn't have been your intention, could it?

The error message could use some improvement, I suppose, but I'm not 
sure how to make it better.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-08 18:50                               ` Dmitry Gutov
@ 2022-10-10  8:10                                 ` Eli Zaretskii
  2022-10-11  2:12                                   ` Dmitry Gutov
  0 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-10  8:10 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: gerd.moellmann, 58158, monnier

> Date: Sat, 8 Oct 2022 21:50:39 +0300
> Cc: gerd.moellmann@gmail.com, 58158@debbugs.gnu.org, monnier@iro.umontreal.ca
> From: Dmitry Gutov <dgutov@yandex.ru>
> 
> > Btw, what am I doing wrong below?
> > 
> >   emacs -Q
> >   C-x C-f src/character.h RET
> >   M-x visit-tags-table RET RET
> >   M-. char_string RET
> >   r whatever RET
> > 
> > Unexpected result: "No suitable matches here".  Huh? what did I miss?
> 
> We can't replace over "find definition" matches: they are more abstract 
> and don't contain the necessary information to perform the replacement 
> (such as the length of a match, for instance).
> 
> And such xrefs might navigate you to the beginning of the line, for 
> example, rather than to the beginning of the name.
> 
> But that makes sense, doesn't it? If replacing over "find definitions" 
> results worked fine, in the end you would get a codebase where all 
> declarations of a method 'foo' got renamed, but all callsites of it 
> remain unchanged. That couldn't have been your intention, could it?
> 
> The error message could use some improvement, I suppose, but I'm not 
> sure how to make it better.

I tried to improve the situation, both in the error message, the doc
string, and the manual.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-10  8:10                                 ` Eli Zaretskii
@ 2022-10-11  2:12                                   ` Dmitry Gutov
  2022-10-11  6:37                                     ` Eli Zaretskii
  0 siblings, 1 reply; 68+ messages in thread
From: Dmitry Gutov @ 2022-10-11  2:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gerd.moellmann, 58158, monnier

On 10.10.2022 11:10, Eli Zaretskii wrote:
>> Date: Sat, 8 Oct 2022 21:50:39 +0300
>> Cc:gerd.moellmann@gmail.com,58158@debbugs.gnu.org,monnier@iro.umontreal.ca
>> From: Dmitry Gutov<dgutov@yandex.ru>
>>
>>> Btw, what am I doing wrong below?
>>>
>>>    emacs -Q
>>>    C-x C-f src/character.h RET
>>>    M-x visit-tags-table RET RET
>>>    M-. char_string RET
>>>    r whatever RET
>>>
>>> Unexpected result: "No suitable matches here".  Huh? what did I miss?
>> We can't replace over "find definition" matches: they are more abstract
>> and don't contain the necessary information to perform the replacement
>> (such as the length of a match, for instance).
>>
>> And such xrefs might navigate you to the beginning of the line, for
>> example, rather than to the beginning of the name.
>>
>> But that makes sense, doesn't it? If replacing over "find definitions"
>> results worked fine, in the end you would get a codebase where all
>> declarations of a method 'foo' got renamed, but all callsites of it
>> remain unchanged. That couldn't have been your intention, could it?
>>
>> The error message could use some improvement, I suppose, but I'm not
>> sure how to make it better.
> I tried to improve the situation, both in the error message, the doc
> string, and the manual.

It's probably better now, but still likely confusing.

What is a "subset of matches"? The user makes a search, gets a bunch of 
matches. Is it fair to call them "only a subset" is the user only 
searched for definitions?

Or to take another example, the user can search for some regexp inside a 
particular directly, with dired-do-find-regexp. Imagine that that 
directory is not the whole project (perhaps just a minor subdirectory). 
Would it be fair to call the results "only a subset" then? But 
xref-query-replace-in-results will work in that case, because the search 
returns values which have enough info to perform the replacements.

Perhaps we should make the error very specific, like "you can't replace 
inside xref-find-definitions results". Since that is going to be the 
exception in like 99.9% of the cases.

It's possible for other backend commands (such as find-references) to 
return unsuitable xref values in third-party backends, or for other code 
to use xref-show-xrefs with such, but those will be really very rare, if 
happen at all.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11  2:12                                   ` Dmitry Gutov
@ 2022-10-11  6:37                                     ` Eli Zaretskii
  2022-10-11 11:36                                       ` xref-query-replace-in-results error message after xref-find-definitions, was: " Dmitry Gutov
  0 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-11  6:37 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: gerd.moellmann, 58158, monnier

> Date: Tue, 11 Oct 2022 05:12:11 +0300
> Cc: gerd.moellmann@gmail.com, 58158@debbugs.gnu.org, monnier@iro.umontreal.ca
> From: Dmitry Gutov <dgutov@yandex.ru>
> 
> What is a "subset of matches"?

Feel free to suggest a less vague description.  The idea is that the
list in Xref buffer doesn't show all the references to the identifier,
making renaming infeasible.

> Perhaps we should make the error very specific, like "you can't replace 
> inside xref-find-definitions results". Since that is going to be the 
> exception in like 99.9% of the cases.

That'd be my preference, but what are those 0.1% of cases where the
Xref buffer produced by other commands could fit?

More generally, what exactly does xref.el test to produce the error
message, and how to describe that in user-level terms?

> It's possible for other backend commands (such as find-references) to 
> return unsuitable xref values in third-party backends, or for other code 
> to use xref-show-xrefs with such, but those will be really very rare, if 
> happen at all.

You are saying that 'r' is only useful after M-?, is that right?  The
manual says so, but the manual doesn't have to say "the whole truth".
The doc string should.





^ permalink raw reply	[flat|nested] 68+ messages in thread

* xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11  6:37                                     ` Eli Zaretskii
@ 2022-10-11 11:36                                       ` Dmitry Gutov
  2022-10-11 11:51                                         ` Eli Zaretskii
  0 siblings, 1 reply; 68+ messages in thread
From: Dmitry Gutov @ 2022-10-11 11:36 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

Moving from Debbugs here.

On 11.10.2022 09:37, Eli Zaretskii wrote:
>> Date: Tue, 11 Oct 2022 05:12:11 +0300
>> Cc: gerd.moellmann@gmail.com, 58158@debbugs.gnu.org, monnier@iro.umontreal.ca
>> From: Dmitry Gutov <dgutov@yandex.ru>
>>
>> What is a "subset of matches"?
> 
> Feel free to suggest a less vague description.  The idea is that the
> list in Xref buffer doesn't show all the references to the identifier,
> making renaming infeasible.

How about:

   Cannot perform replacements in this search's results

>> Perhaps we should make the error very specific, like "you can't replace
>> inside xref-find-definitions results". Since that is going to be the
>> exception in like 99.9% of the cases.
> 
> That'd be my preference, but what are those 0.1% of cases where the
> Xref buffer produced by other commands could fit?

I suppose they will be covered by the above message, while in the manual 
you can explain it in more simple terms, since you don't need to worry 
about third-party code as much.

> More generally, what exactly does xref.el test to produce the error
> message, and how to describe that in user-level terms?

It tests whether the method xref-match-length returns non-nil for any 
search results. When they do, it would identify them as "match xrefs" 
(mentioned in the Commentary).

But I suppose that clashes with the terminology you prefer to use.

>> It's possible for other backend commands (such as find-references) to
>> return unsuitable xref values in third-party backends, or for other code
>> to use xref-show-xrefs with such, but those will be really very rare, if
>> happen at all.
> 
> You are saying that 'r' is only useful after M-?, is that right?  The
> manual says so, but the manual doesn't have to say "the whole truth".
> The doc string should.

It works after dired-do-find-regexp and project-find-regexp as well.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 11:36                                       ` xref-query-replace-in-results error message after xref-find-definitions, was: " Dmitry Gutov
@ 2022-10-11 11:51                                         ` Eli Zaretskii
  2022-10-11 12:10                                           ` Dmitry Gutov
  2022-10-11 14:04                                           ` Stefan Monnier
  0 siblings, 2 replies; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-11 11:51 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

> Date: Tue, 11 Oct 2022 14:36:11 +0300
> Cc: emacs-devel <emacs-devel@gnu.org>
> From: Dmitry Gutov <dgutov@yandex.ru>
> 
> Moving from Debbugs here.
> 
> On 11.10.2022 09:37, Eli Zaretskii wrote:
> >> Date: Tue, 11 Oct 2022 05:12:11 +0300
> >> Cc: gerd.moellmann@gmail.com, 58158@debbugs.gnu.org, monnier@iro.umontreal.ca
> >> From: Dmitry Gutov <dgutov@yandex.ru>
> >>
> >> What is a "subset of matches"?
> > 
> > Feel free to suggest a less vague description.  The idea is that the
> > list in Xref buffer doesn't show all the references to the identifier,
> > making renaming infeasible.
> 
> How about:
> 
>    Cannot perform replacements in this search's results

This is similar to the original message.  Its problem is that it
states the fact, but doesn't attempt to explain it, and thus doesn't
give a clue what the user did wrong and how to fix that.

> > More generally, what exactly does xref.el test to produce the error
> > message, and how to describe that in user-level terms?
> 
> It tests whether the method xref-match-length returns non-nil for any 
> search results. When they do, it would identify them as "match xrefs" 
> (mentioned in the Commentary).
> 
> But I suppose that clashes with the terminology you prefer to use.

If it's possible to come up with the semantics of xref-match-length or
of "match xrefs", maybe that could be useful.  The commentary just
says the "correspond to search result", which is not very useful for
this purpose.

> > You are saying that 'r' is only useful after M-?, is that right?  The
> > manual says so, but the manual doesn't have to say "the whole truth".
> > The doc string should.
> 
> It works after dired-do-find-regexp and project-find-regexp as well.

So wed cannot say something like "This can only be used after M-?",
sigh...

I still have no idea how to improve the error message.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 11:51                                         ` Eli Zaretskii
@ 2022-10-11 12:10                                           ` Dmitry Gutov
  2022-10-11 12:17                                             ` Eli Zaretskii
  2022-10-11 14:04                                           ` Stefan Monnier
  1 sibling, 1 reply; 68+ messages in thread
From: Dmitry Gutov @ 2022-10-11 12:10 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

On 11.10.2022 14:51, Eli Zaretskii wrote:
>> Date: Tue, 11 Oct 2022 14:36:11 +0300
>> Cc: emacs-devel <emacs-devel@gnu.org>
>> From: Dmitry Gutov <dgutov@yandex.ru>
>>
>> Moving from Debbugs here.
>>
>> On 11.10.2022 09:37, Eli Zaretskii wrote:
>>>> Date: Tue, 11 Oct 2022 05:12:11 +0300
>>>> Cc: gerd.moellmann@gmail.com, 58158@debbugs.gnu.org, monnier@iro.umontreal.ca
>>>> From: Dmitry Gutov <dgutov@yandex.ru>
>>>>
>>>> What is a "subset of matches"?
>>>
>>> Feel free to suggest a less vague description.  The idea is that the
>>> list in Xref buffer doesn't show all the references to the identifier,
>>> making renaming infeasible.
>>
>> How about:
>>
>>     Cannot perform replacements in this search's results
> 
> This is similar to the original message.

It is, because it tries to be accurate foremost, covering all potential 
situations.

But, like I explained, your new message is not much better: it still 
tries to be "high-level", rather than stating particulars, and while 
doing that, contradicts some objective facts.

It might be worth it if it were very clear to the user and true in 99% 
of the situations, but that doesn't looks like the case.

> Its problem is that it
> states the fact, but doesn't attempt to explain it, and thus doesn't
> give a clue what the user did wrong and how to fix that.

How does one explain that we cannot replace in xref-find-definitions 
results? E.g. because the abstract we use for this operations (to 
support different backends) doesn't give us enough information to 
perform that replacement.

And also because replacing in xref-find-definitions results doesn't make 
sense to begin with.

>>> More generally, what exactly does xref.el test to produce the error
>>> message, and how to describe that in user-level terms?
>>
>> It tests whether the method xref-match-length returns non-nil for any
>> search results. When they do, it would identify them as "match xrefs"
>> (mentioned in the Commentary).
>>
>> But I suppose that clashes with the terminology you prefer to use.
> 
> If it's possible to come up with the semantics of xref-match-length or
> of "match xrefs", maybe that could be useful.

Those are basically generalized versions of xref file matches (also 
almost same info as what M-x Grep provides), which contain the line 
number and column, and length of the match. We obtain the first two 
pieces of info lazily, but we need the last one as well.

> The commentary just
> says the "correspond to search result", which is not very useful for
> this purpose.

Search result as in result of a "full scan" of the directory. As opposed 
to looking in some small index which contains the definitions. At least 
what's what I was thinking of, probably.

But the find-references search could also be sped up with an index, so 
this is probably not worth differentiating in these terms.

>>> You are saying that 'r' is only useful after M-?, is that right?  The
>>> manual says so, but the manual doesn't have to say "the whole truth".
>>> The doc string should.
>>
>> It works after dired-do-find-regexp and project-find-regexp as well.
> 
> So wed cannot say something like "This can only be used after M-?",
> sigh...
> 
> I still have no idea how to improve the error message.

Perhaps I should remind that xref-find-definitions is still the main 
exception -- where this command doesn't work.

We also had some talks previously where it's been suggested that we 
should try to show different UIs by default, for xref-find-definitions 
results, and for other xref searches. IIRC you disagreed.

I tried to make a poll for that idea, but there were no conclusive 
choice on what alternative xref-show-definitions-function to use.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 12:10                                           ` Dmitry Gutov
@ 2022-10-11 12:17                                             ` Eli Zaretskii
  2022-10-11 12:44                                               ` Dmitry Gutov
  0 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-11 12:17 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

> Date: Tue, 11 Oct 2022 15:10:47 +0300
> Cc: emacs-devel@gnu.org
> From: Dmitry Gutov <dgutov@yandex.ru>
> 
> >> How about:
> >>
> >>     Cannot perform replacements in this search's results
> > 
> > This is similar to the original message.
> 
> It is, because it tries to be accurate foremost, covering all potential 
> situations.
> 
> But, like I explained, your new message is not much better: it still 
> tries to be "high-level", rather than stating particulars, and while 
> doing that, contradicts some objective facts.
> 
> It might be worth it if it were very clear to the user and true in 99% 
> of the situations, but that doesn't looks like the case.
> 
> > Its problem is that it
> > states the fact, but doesn't attempt to explain it, and thus doesn't
> > give a clue what the user did wrong and how to fix that.
> 
> How does one explain that we cannot replace in xref-find-definitions 
> results?

That's what the "subset of matches of identifier" part attempts to do.

> And also because replacing in xref-find-definitions results doesn't make 
> sense to begin with.

I agree that it makes no sense.  The problem is how to say that in a
general enough way.

> > If it's possible to come up with the semantics of xref-match-length or
> > of "match xrefs", maybe that could be useful.
> 
> Those are basically generalized versions of xref file matches (also 
> almost same info as what M-x Grep provides), which contain the line 
> number and column, and length of the match. We obtain the first two 
> pieces of info lazily, but we need the last one as well.

And why do the results of xref-find-definitions lack that?

> > I still have no idea how to improve the error message.
> 
> Perhaps I should remind that xref-find-definitions is still the main 
> exception -- where this command doesn't work.

But not the only one?

> We also had some talks previously where it's been suggested that we 
> should try to show different UIs by default, for xref-find-definitions 
> results, and for other xref searches. IIRC you disagreed.

'r' is just one command which is sensitive to the differences.  AFAIR,
most other commands aren't.  So it makes sense to use the same UI.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 12:17                                             ` Eli Zaretskii
@ 2022-10-11 12:44                                               ` Dmitry Gutov
  2022-10-11 12:55                                                 ` Eli Zaretskii
  0 siblings, 1 reply; 68+ messages in thread
From: Dmitry Gutov @ 2022-10-11 12:44 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

On 11.10.2022 15:17, Eli Zaretskii wrote:

>>> Its problem is that it
>>> states the fact, but doesn't attempt to explain it, and thus doesn't
>>> give a clue what the user did wrong and how to fix that.
>>
>> How does one explain that we cannot replace in xref-find-definitions
>> results?
> 
> That's what the "subset of matches of identifier" part attempts to do.

A high-level and not very accurate description, because it's only 
relevant for the difference between xref-find-definitions vs 
xref-find-references, but not when the *-find-regexp commands come into 
play.

>> And also because replacing in xref-find-definitions results doesn't make
>> sense to begin with.
> 
> I agree that it makes no sense.  The problem is how to say that in a
> general enough way.

"Not supported" is not too terrible an error message if we are sure the 
user is trying to do something they shouldn't even attempt to.

But we can try to be helpful by offering an alternative:

   Cannot replace in this search; to rename a symbol, invoke 
\\[xref-find-references] first

>>> If it's possible to come up with the semantics of xref-match-length or
>>> of "match xrefs", maybe that could be useful.
>>
>> Those are basically generalized versions of xref file matches (also
>> almost same info as what M-x Grep provides), which contain the line
>> number and column, and length of the match. We obtain the first two
>> pieces of info lazily, but we need the last one as well.
> 
> And why do the results of xref-find-definitions lack that?

So that the backend isn't forced to provide info that's harder to get, 
and that we don't use anyway. E.g. M-x find-function just brings you to 
BOL rather than to the beginning of the symbol.

>>> I still have no idea how to improve the error message.
>>
>> Perhaps I should remind that xref-find-definitions is still the main
>> exception -- where this command doesn't work.
> 
> But not the only one?

The only known one, so far. Although it might depend on the backend as 
well. The built-in backends are going to fail, but it seems like 
lsp-mode at least returns "match xrefs" for all searches. Maybe Eglot 
too, I haven't checked.

That would mean that one 'r' can work in lsp-mode's 
xref-find-definitions results (they define a bunch of custom commands 
like lsp-find-definition and lsp-find-declaration, but that probably 
doesn't matter). Not sure if we should do something about that.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 12:44                                               ` Dmitry Gutov
@ 2022-10-11 12:55                                                 ` Eli Zaretskii
  2022-10-11 14:55                                                   ` Dmitry Gutov
  0 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-11 12:55 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

> Date: Tue, 11 Oct 2022 15:44:18 +0300
> Cc: emacs-devel@gnu.org
> From: Dmitry Gutov <dgutov@yandex.ru>
> 
> On 11.10.2022 15:17, Eli Zaretskii wrote:
> 
> >>> Its problem is that it
> >>> states the fact, but doesn't attempt to explain it, and thus doesn't
> >>> give a clue what the user did wrong and how to fix that.
> >>
> >> How does one explain that we cannot replace in xref-find-definitions
> >> results?
> > 
> > That's what the "subset of matches of identifier" part attempts to do.
> 
> A high-level and not very accurate description, because it's only 
> relevant for the difference between xref-find-definitions vs 
> xref-find-references, but not when the *-find-regexp commands come into 
> play.

I know.  As I said, suggestions for better wording will be moist
welcome.

> But we can try to be helpful by offering an alternative:
> 
>    Cannot replace in this search; to rename a symbol, invoke 
> \\[xref-find-references] first

But then we'd need to name the other 2 commands as well, to be
accurate, yes?

> >> Perhaps I should remind that xref-find-definitions is still the main
> >> exception -- where this command doesn't work.
> > 
> > But not the only one?
> 
> The only known one, so far.

So maybe just saying

  Cannot do global replacement using results of \\[xref-find-definitions]

should be okay?

> That would mean that one 'r' can work in lsp-mode's 
> xref-find-definitions results (they define a bunch of custom commands 
> like lsp-find-definition and lsp-find-declaration, but that probably 
> doesn't matter). Not sure if we should do something about that.

If 'r' happens to work in that case, we don't have to worry about the
error message, right?



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 11:51                                         ` Eli Zaretskii
  2022-10-11 12:10                                           ` Dmitry Gutov
@ 2022-10-11 14:04                                           ` Stefan Monnier
  2022-10-11 14:07                                             ` Stefan Monnier
  2022-10-11 15:37                                             ` Eli Zaretskii
  1 sibling, 2 replies; 68+ messages in thread
From: Stefan Monnier @ 2022-10-11 14:04 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Dmitry Gutov, emacs-devel

>> >> What is a "subset of matches"?
[...]
>>    Cannot perform replacements in this search's results

Not sure if it's been proposed already, but how 'bout something along
the lines of "There may be more matches <elsewhere>".


        Stefan




^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 14:04                                           ` Stefan Monnier
@ 2022-10-11 14:07                                             ` Stefan Monnier
  2022-10-11 15:07                                               ` Dmitry Gutov
  2022-10-11 15:37                                             ` Eli Zaretskii
  1 sibling, 1 reply; 68+ messages in thread
From: Stefan Monnier @ 2022-10-11 14:07 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Dmitry Gutov, emacs-devel

Stefan Monnier [2022-10-11 10:04:28] wrote:
>>> >> What is a "subset of matches"?
> [...]
>>>    Cannot perform replacements in this search's results
>
> Not sure if it's been proposed already, but how 'bout something along
> the lines of "There may be more matches <elsewhere>".

Or "This list is probably incomplete"?


        Stefan




^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 12:55                                                 ` Eli Zaretskii
@ 2022-10-11 14:55                                                   ` Dmitry Gutov
  2022-10-11 16:01                                                     ` Eli Zaretskii
  0 siblings, 1 reply; 68+ messages in thread
From: Dmitry Gutov @ 2022-10-11 14:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

On 11.10.2022 15:55, Eli Zaretskii wrote:

>> But we can try to be helpful by offering an alternative:
>>
>>     Cannot replace in this search; to rename a symbol, invoke
>> \\[xref-find-references] first
> 
> But then we'd need to name the other 2 commands as well, to be
> accurate, yes?

If our conclusion is that the error is due to user trying to rename a 
symbol (and failing because xref-find-definitions's results don't allow 
them to do so), then xref-find-references is exactly the right suggestion.

Users who try to replace in regexp search matches don't see the error.

>>>> Perhaps I should remind that xref-find-definitions is still the main
>>>> exception -- where this command doesn't work.
>>>
>>> But not the only one?
>>
>> The only known one, so far.
> 
> So maybe just saying
> 
>    Cannot do global replacement using results of \\[xref-find-definitions]
> 
> should be okay?

Isn't it almost the same as I suggested upthread? Except I suggested 
"this search" instead of naming the specific command.

Do you think naming it will be helpful enough to sacrifice the 10% 
accuracy of the message? I suppose someone might have indeed forgotten 
that they did the search using xref-find-definitions.

>> That would mean that one 'r' can work in lsp-mode's
>> xref-find-definitions results (they define a bunch of custom commands
>> like lsp-find-definition and lsp-find-declaration, but that probably
>> doesn't matter). Not sure if we should do something about that.
> 
> If 'r' happens to work in that case, we don't have to worry about the
> error message, right?

That's correct, but having the command succeed might be a problem by 
itself, couldn't it? It will rename the definitions (and/or 
declarations), but not other occurrences.

If we go in from this direction, we can have 
xref-show-definitions-buffer (the default 
xref-show-definitions-function) ensure that the binding for 'r' is set 
to some command that always reports an error (like 'cannot replace in 
definitions'), or is unbound.

This would do nothing for custom values of 
xref-show-definitions-function, but should remove most of the confusion 
with default configuration. And some non-default ones as well (lsp-mode 
doesn't change the value of xref-show-definitions-function).

If the docstring of xref-show-definitions-function looks okay to you, we 
can use its vocabulary.

   Cannot replace in definition search results

should cover xref-find-definitions, lsp-find-definition and 
lsp-find-declaration. Wouldn't help with lsp-find-implementation, though 
(its results are also questionable WRT renaming because they don't 
include all references either), but it won't make it worse.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 14:07                                             ` Stefan Monnier
@ 2022-10-11 15:07                                               ` Dmitry Gutov
  0 siblings, 0 replies; 68+ messages in thread
From: Dmitry Gutov @ 2022-10-11 15:07 UTC (permalink / raw)
  To: Stefan Monnier, Eli Zaretskii; +Cc: emacs-devel

On 11.10.2022 17:07, Stefan Monnier wrote:
> Stefan Monnier [2022-10-11 10:04:28] wrote:
>>>>>> What is a "subset of matches"?
>> [...]
>>>>     Cannot perform replacements in this search's results
>> Not sure if it's been proposed already, but how 'bout something along
>> the lines of "There may be more matches <elsewhere>".
> Or "This list is probably incomplete"?

That's the logical reason, but not really the technical one.

Although we might make a stronger effort to align these two (see my 
previous message in this thread).



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 14:04                                           ` Stefan Monnier
  2022-10-11 14:07                                             ` Stefan Monnier
@ 2022-10-11 15:37                                             ` Eli Zaretskii
  1 sibling, 0 replies; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-11 15:37 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: dgutov, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Dmitry Gutov <dgutov@yandex.ru>,  emacs-devel@gnu.org
> Date: Tue, 11 Oct 2022 10:04:28 -0400
> 
> >> >> What is a "subset of matches"?
> [...]
> >>    Cannot perform replacements in this search's results
> 
> Not sure if it's been proposed already, but how 'bout something along
> the lines of "There may be more matches <elsewhere>".

Thanks.  But that doesn't sound like an error message to me.  That
there are more matches doesn't make it clear why the ones that are
present cannot be used.  It requires a lengthy explanation or
inference.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 14:55                                                   ` Dmitry Gutov
@ 2022-10-11 16:01                                                     ` Eli Zaretskii
  2022-10-11 16:41                                                       ` Dmitry Gutov
  0 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-11 16:01 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

> Date: Tue, 11 Oct 2022 17:55:02 +0300
> Cc: emacs-devel@gnu.org
> From: Dmitry Gutov <dgutov@yandex.ru>
> 
> On 11.10.2022 15:55, Eli Zaretskii wrote:
> 
> >> But we can try to be helpful by offering an alternative:
> >>
> >>     Cannot replace in this search; to rename a symbol, invoke
> >> \\[xref-find-references] first
> > 
> > But then we'd need to name the other 2 commands as well, to be
> > accurate, yes?
> 
> If our conclusion is that the error is due to user trying to rename a 
> symbol (and failing because xref-find-definitions's results don't allow 
> them to do so), then xref-find-references is exactly the right suggestion.

That's true.

> > So maybe just saying
> > 
> >    Cannot do global replacement using results of \\[xref-find-definitions]
> > 
> > should be okay?
> 
> Isn't it almost the same as I suggested upthread? Except I suggested 
> "this search" instead of naming the specific command.

I'm not trying to argue, I'm trying to find the best message text.  It
doesn't matter who suggested it first, what matters whether it is
accurate and self-explanatory.

> Do you think naming it will be helpful enough to sacrifice the 10% 
> accuracy of the message? I suppose someone might have indeed forgotten 
> that they did the search using xref-find-definitions.

What are the 10% of inaccuracy?  If the message will only ever be
shown when 'r' is invoked after M-., then what is inaccurate in it?

> >> That would mean that one 'r' can work in lsp-mode's
> >> xref-find-definitions results (they define a bunch of custom commands
> >> like lsp-find-definition and lsp-find-declaration, but that probably
> >> doesn't matter). Not sure if we should do something about that.
> > 
> > If 'r' happens to work in that case, we don't have to worry about the
> > error message, right?
> 
> That's correct, but having the command succeed might be a problem by 
> itself, couldn't it? It will rename the definitions (and/or 
> declarations), but not other occurrences.

No error message could possibly prevent that from happening, could it?

> If we go in from this direction, we can have 
> xref-show-definitions-buffer (the default 
> xref-show-definitions-function) ensure that the binding for 'r' is set 
> to some command that always reports an error (like 'cannot replace in 
> definitions'), or is unbound.

But users can always invoke the command by name as well.

> This would do nothing for custom values of 
> xref-show-definitions-function, but should remove most of the confusion 
> with default configuration. And some non-default ones as well (lsp-mode 
> doesn't change the value of xref-show-definitions-function).
> 
> If the docstring of xref-show-definitions-function looks okay to you, we 
> can use its vocabulary.
> 
>    Cannot replace in definition search results
> 
> should cover xref-find-definitions, lsp-find-definition and 
> lsp-find-declaration. Wouldn't help with lsp-find-implementation, though 
> (its results are also questionable WRT renaming because they don't 
> include all references either), but it won't make it worse.

Hmm... maybe

  Cannot perform global replacement in find-definition results

Another idea would be for the error message to be constructed
dynamically, and include the precise command that produced the Xref
buffer, if xref.el could record that in some buffer-local variable.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 16:01                                                     ` Eli Zaretskii
@ 2022-10-11 16:41                                                       ` Dmitry Gutov
  2022-10-11 16:50                                                         ` Eli Zaretskii
  0 siblings, 1 reply; 68+ messages in thread
From: Dmitry Gutov @ 2022-10-11 16:41 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

On 11.10.2022 19:01, Eli Zaretskii wrote:

>>> So maybe just saying
>>>
>>>     Cannot do global replacement using results of \\[xref-find-definitions]
>>>
>>> should be okay?
>>
>> Isn't it almost the same as I suggested upthread? Except I suggested
>> "this search" instead of naming the specific command.
> 
> I'm not trying to argue, I'm trying to find the best message text.  It
> doesn't matter who suggested it first, what matters whether it is
> accurate and self-explanatory.

I wasn't playing "who said it first" either, but pointing at the 
previous suggestion as a little more inherently-accurate.

>> Do you think naming it will be helpful enough to sacrifice the 10%
>> accuracy of the message? I suppose someone might have indeed forgotten
>> that they did the search using xref-find-definitions.
> 
> What are the 10% of inaccuracy?

Sorry, losing 100% accuracy, to get a slightly smaller percentage.

> If the message will only ever be
> shown when 'r' is invoked after M-., then what is inaccurate in it?

Almost only ever. With potential for exceptions, unless we try to 
enforce their absence.

>>>> That would mean that one 'r' can work in lsp-mode's
>>>> xref-find-definitions results (they define a bunch of custom commands
>>>> like lsp-find-definition and lsp-find-declaration, but that probably
>>>> doesn't matter). Not sure if we should do something about that.
>>>
>>> If 'r' happens to work in that case, we don't have to worry about the
>>> error message, right?
>>
>> That's correct, but having the command succeed might be a problem by
>> itself, couldn't it? It will rename the definitions (and/or
>> declarations), but not other occurrences.
> 
> No error message could possibly prevent that from happening, could it?

Only if it happens somewhere else, or if the check before the errors is 
changed significantly.

>> If we go in from this direction, we can have
>> xref-show-definitions-buffer (the default
>> xref-show-definitions-function) ensure that the binding for 'r' is set
>> to some command that always reports an error (like 'cannot replace in
>> definitions'), or is unbound.
> 
> But users can always invoke the command by name as well.

That's, uh, true. But having commands intended for one major mode 
silently failing (or doing that in a weird fashion) when invoked with 
'M-x' in another major mode has not usually been a concern for us.

>> This would do nothing for custom values of
>> xref-show-definitions-function, but should remove most of the confusion
>> with default configuration. And some non-default ones as well (lsp-mode
>> doesn't change the value of xref-show-definitions-function).
>>
>> If the docstring of xref-show-definitions-function looks okay to you, we
>> can use its vocabulary.
>>
>>     Cannot replace in definition search results
>>
>> should cover xref-find-definitions, lsp-find-definition and
>> lsp-find-declaration. Wouldn't help with lsp-find-implementation, though
>> (its results are also questionable WRT renaming because they don't
>> include all references either), but it won't make it worse.
> 
> Hmm... maybe
> 
>    Cannot perform global replacement in find-definition results
> 
> Another idea would be for the error message to be constructed
> dynamically, and include the precise command that produced the Xref
> buffer, if xref.el could record that in some buffer-local variable.

I suppose it could. But then some backend (such as lsp or possibly 
eglot) might return 'definitions' results in format suitable for 
replacements, and that will mean that one can replace in 
xref-find-definitions's results, just with some backends but not others.

And with that, the error message

   Cannot do global replacement using results of \\[xref-find-definitions]

shown to the same user at a different time (perhaps when they're editing 
Elisp) will become a lie.

And then, okay, we could try to add the name of the backend symbol to 
the error message as well, but it's much harder to capture that one, 
especially given that not every command using Xref output will go 
through xref-backend-functions (project-find-regexp is a counter-example).



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 16:41                                                       ` Dmitry Gutov
@ 2022-10-11 16:50                                                         ` Eli Zaretskii
  2022-10-11 20:31                                                           ` Dmitry Gutov
  0 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-11 16:50 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

> Date: Tue, 11 Oct 2022 19:41:35 +0300
> Cc: emacs-devel@gnu.org
> From: Dmitry Gutov <dgutov@yandex.ru>
> 
> >> This would do nothing for custom values of
> >> xref-show-definitions-function, but should remove most of the confusion
> >> with default configuration. And some non-default ones as well (lsp-mode
> >> doesn't change the value of xref-show-definitions-function).
> >>
> >> If the docstring of xref-show-definitions-function looks okay to you, we
> >> can use its vocabulary.
> >>
> >>     Cannot replace in definition search results
> >>
> >> should cover xref-find-definitions, lsp-find-definition and
> >> lsp-find-declaration. Wouldn't help with lsp-find-implementation, though
> >> (its results are also questionable WRT renaming because they don't
> >> include all references either), but it won't make it worse.
> > 
> > Hmm... maybe
> > 
> >    Cannot perform global replacement in find-definition results
> > 
> > Another idea would be for the error message to be constructed
> > dynamically, and include the precise command that produced the Xref
> > buffer, if xref.el could record that in some buffer-local variable.
> 
> I suppose it could. But then some backend (such as lsp or possibly 
> eglot) might return 'definitions' results in format suitable for 
> replacements, and that will mean that one can replace in 
> xref-find-definitions's results, just with some backends but not others.
> 
> And with that, the error message
> 
>    Cannot do global replacement using results of \\[xref-find-definitions]
> 
> shown to the same user at a different time (perhaps when they're editing 
> Elisp) will become a lie.
> 
> And then, okay, we could try to add the name of the backend symbol to 
> the error message as well, but it's much harder to capture that one, 
> especially given that not every command using Xref output will go 
> through xref-backend-functions (project-find-regexp is a counter-example).

So is this:

  Cannot perform global replacement in find-definition results

the best that can be done?  It sounds like no alternative is
significantly better.




^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 16:50                                                         ` Eli Zaretskii
@ 2022-10-11 20:31                                                           ` Dmitry Gutov
  2022-10-12  5:17                                                             ` Eli Zaretskii
  0 siblings, 1 reply; 68+ messages in thread
From: Dmitry Gutov @ 2022-10-11 20:31 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

On 11.10.2022 19:50, Eli Zaretskii wrote:

> So is this:
> 
>    Cannot perform global replacement in find-definition results
> 
> the best that can be done?  It sounds like no alternative is
> significantly better.

Perhaps.

Let's drop the "global" adjective, though: whether the command works 
"globally", "locally", or etc, depends on how the user made the search.

Then we can make this the error message and wait and see until the next 
time anybody complains about the new phrasing. Probably after Emacs 29.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-11 20:31                                                           ` Dmitry Gutov
@ 2022-10-12  5:17                                                             ` Eli Zaretskii
  2022-10-12 10:06                                                               ` John Yates
  2022-10-12 13:47                                                               ` Dmitry Gutov
  0 siblings, 2 replies; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-12  5:17 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

> Date: Tue, 11 Oct 2022 23:31:01 +0300
> Cc: emacs-devel@gnu.org
> From: Dmitry Gutov <dgutov@yandex.ru>
> 
> On 11.10.2022 19:50, Eli Zaretskii wrote:
> 
> > So is this:
> > 
> >    Cannot perform global replacement in find-definition results
> > 
> > the best that can be done?  It sounds like no alternative is
> > significantly better.
> 
> Perhaps.
> 
> Let's drop the "global" adjective, though: whether the command works 
> "globally", "locally", or etc, depends on how the user made the search.

The "global" part is important, though: it's supposed to hint on why
find-definition results cannot be used.  The opposite of "global" here
is "partial", not "local".  If you can suggest a better word for
"global" here, please do.

> Then we can make this the error message and wait and see until the next 
> time anybody complains about the new phrasing. Probably after Emacs 29.

Yep.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-12  5:17                                                             ` Eli Zaretskii
@ 2022-10-12 10:06                                                               ` John Yates
  2022-10-12 10:17                                                                 ` Eli Zaretskii
  2022-10-12 13:47                                                               ` Dmitry Gutov
  1 sibling, 1 reply; 68+ messages in thread
From: John Yates @ 2022-10-12 10:06 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Dmitry Gutov, emacs-devel

On Wed, Oct 12, 2022 at 1:18 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> The "global" part is important, though: it's supposed to hint on why
> find-definition results cannot be used.  The opposite of "global" here
> is "partial", not "local".  If you can suggest a better word for
> "global" here, please do.

Clearly the 'global' / 'local' dichotomy is too deeply ingrained in emacs
concepts to allow easy reuse of those terms with even slightly different
meanings.  Perhaps 'full', 'complete', 'total', 'universal', or some such.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-12 10:06                                                               ` John Yates
@ 2022-10-12 10:17                                                                 ` Eli Zaretskii
       [not found]                                                                   ` <CAJnXXogKsM=gMTFi2NivDMHW4A3EBtBtsNDBV3o5vcu2xXfuvw@mail.gmail.com>
  0 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-12 10:17 UTC (permalink / raw)
  To: emacs-devel, John Yates; +Cc: Dmitry Gutov

On October 12, 2022 1:06:22 PM GMT+03:00, John Yates <john@yates-sheets.org> wrote:
> On Wed, Oct 12, 2022 at 1:18 AM Eli Zaretskii <eliz@gnu.org> wrote:
> >
> > The "global" part is important, though: it's supposed to hint on why
> > find-definition results cannot be used.  The opposite of "global" here
> > is "partial", not "local".  If you can suggest a better word for
> > "global" here, please do.
> 
> Clearly the 'global' / 'local' dichotomy is too deeply ingrained in emacs
> concepts to allow easy reuse of those terms with even slightly different
> meanings.  Perhaps 'full', 'complete', 'total', 'universal', or some such.


We are talking about "global replacement", yes?



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
       [not found]                                                                   ` <CAJnXXogKsM=gMTFi2NivDMHW4A3EBtBtsNDBV3o5vcu2xXfuvw@mail.gmail.com>
@ 2022-10-12 13:21                                                                     ` Eli Zaretskii
  2022-10-12 16:12                                                                       ` John Yates
  0 siblings, 1 reply; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-12 13:21 UTC (permalink / raw)
  To: John Yates; +Cc: emacs-devel

> From: John Yates <john@yates-sheets.org>
> Date: Wed, 12 Oct 2022 07:49:06 -0400
> 
> On Wed, Oct 12, 2022 at 6:17 AM Eli Zaretskii <eliz@gnu.org> wrote:
> >
> > On October 12, 2022 1:06:22 PM GMT+03:00, John Yates <john@yates-sheets.org> wrote:
> > > . . .  Perhaps 'full', 'complete', 'total', 'universal', or some such.
> >
> > We are talking about "global replacement", yes?
> 
> Yes we are.  And, IIUC, your point is that the concept of
> "global replacement" is comparably embedded in software
> development.  Hmm...

Not only that, the replacements (pun intended) you proposed don't seem
to fit this context.  What synonyms of "global replacement" exist that
don't use the word "global"?

P.S. I restored the CC to emacs-devel on the assumption that you
omitted it by accident; apologies if that was intentional.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-12  5:17                                                             ` Eli Zaretskii
  2022-10-12 10:06                                                               ` John Yates
@ 2022-10-12 13:47                                                               ` Dmitry Gutov
  2022-10-12 14:05                                                                 ` Eli Zaretskii
  1 sibling, 1 reply; 68+ messages in thread
From: Dmitry Gutov @ 2022-10-12 13:47 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

On 12.10.2022 08:17, Eli Zaretskii wrote:
>> Let's drop the "global" adjective, though: whether the command works
>> "globally", "locally", or etc, depends on how the user made the search.
> The "global" part is important, though: it's supposed to hint on why
> find-definition results cannot be used.  The opposite of "global" here
> is "partial", not "local".  If you can suggest a better word for
> "global" here, please do.

I think you're trying hard to make it clearer, but it still won't have 
100% the intended effect.

And it makes the error more likely to confuse the user and make them 
misunderstand how things work:

1) Saying "Cannot perform global replacement in find-definition 
results", with the explicit qualifier "global", potentially implies that 
a "local" replacement in find-definition results can be done. But it 
cannot. We can't do either currently for technical reasons.

We don't want to do "local" replacements in find-definition results also 
for logical reasons, but that's just the reason why we're not in a hurry 
to remove the technical limitation.

2) The message implies 'r' is limited to "global" replacement. But it 
can easily do "partial" replacement, as long as the command that 
produces the list returns "match xrefs". dired-do-find-regexp, for 
example. Or project-find-regexp, when called with C-u, and the user 
specifies a specific directory. They will return a "partial" list of 
matches, compared to the full project search.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-12 13:47                                                               ` Dmitry Gutov
@ 2022-10-12 14:05                                                                 ` Eli Zaretskii
  0 siblings, 0 replies; 68+ messages in thread
From: Eli Zaretskii @ 2022-10-12 14:05 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

> Date: Wed, 12 Oct 2022 16:47:15 +0300
> Cc: emacs-devel@gnu.org
> From: Dmitry Gutov <dgutov@yandex.ru>
> 
> On 12.10.2022 08:17, Eli Zaretskii wrote:
> >> Let's drop the "global" adjective, though: whether the command works
> >> "globally", "locally", or etc, depends on how the user made the search.
> > The "global" part is important, though: it's supposed to hint on why
> > find-definition results cannot be used.  The opposite of "global" here
> > is "partial", not "local".  If you can suggest a better word for
> > "global" here, please do.
> 
> I think you're trying hard to make it clearer, but it still won't have 
> 100% the intended effect.
> 
> And it makes the error more likely to confuse the user and make them 
> misunderstand how things work:
> 
> 1) Saying "Cannot perform global replacement in find-definition 
> results", with the explicit qualifier "global", potentially implies that 
> a "local" replacement in find-definition results can be done. But it 
> cannot. We can't do either currently for technical reasons.
> 
> We don't want to do "local" replacements in find-definition results also 
> for logical reasons, but that's just the reason why we're not in a hurry 
> to remove the technical limitation.
> 
> 2) The message implies 'r' is limited to "global" replacement. But it 
> can easily do "partial" replacement, as long as the command that 
> produces the list returns "match xrefs". dired-do-find-regexp, for 
> example. Or project-find-regexp, when called with C-u, and the user 
> specifies a specific directory. They will return a "partial" list of 
> matches, compared to the full project search.

Sorry, I'm unconvinced.  AFAICT, you are reiterating issues and
arguments we already have been through.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: xref-query-replace-in-results error message after xref-find-definitions, was: Re: bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-10-12 13:21                                                                     ` Eli Zaretskii
@ 2022-10-12 16:12                                                                       ` John Yates
  0 siblings, 0 replies; 68+ messages in thread
From: John Yates @ 2022-10-12 16:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

On Wed, Oct 12, 2022 at 9:20 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> Not only that, the replacements (pun intended) you proposed don't seem
> to fit this context.

I agree.  Chalk it up to a "senior moment" :-)

> What synonyms of "global replacement" exist that
> don't use the word "global"?

A synonym search suggests "universal" or "galactic" :-)

> P.S. I restored the CC to emacs-devel on the assumption that you
> omitted it by accident; apologies if that was intentional.

I do not always remember to use reply-all.  Thank you.



^ permalink raw reply	[flat|nested] 68+ messages in thread

* bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful
  2022-09-29  5:29 bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful Gerd Möllmann
  2022-09-29  6:28 ` Eli Zaretskii
  2022-10-06 22:26 ` Matt Armstrong
@ 2023-10-06 13:14 ` Gerd Möllmann
  2 siblings, 0 replies; 68+ messages in thread
From: Gerd Möllmann @ 2023-10-06 13:14 UTC (permalink / raw)
  To: 58158

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> In its current form, interval tree iteration works like this:
>
> 1. Call begin_iteration(T) to iterate over tree T
> 2. do stuff
> 3. Call end_iteration(T)
>
> with the following rules:
>
> - Begin_iteration and end_iteration must be paired.
>
> - There can be only one iteration per tree at a time.  Nested iteration
>   over the same tree is not supported (abort).
>
> - No GC may happen in step 2.  This is because mark_buffer iterates over
>   buffer overlays.
>
> I think this is an exceedingly dangerous design.

Time has passed, and I think this is no longer relevant.
I'm therefore closing this bug.





^ permalink raw reply	[flat|nested] 68+ messages in thread

end of thread, other threads:[~2023-10-06 13:14 UTC | newest]

Thread overview: 68+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-29  5:29 bug#58158: 29.0.50; [overlay] Interval tree iteration considered harmful Gerd Möllmann
2022-09-29  6:28 ` Eli Zaretskii
2022-09-29  7:03   ` Gerd Möllmann
2022-09-29  8:08     ` Eli Zaretskii
2022-09-29  9:09       ` Gerd Möllmann
2022-09-29  9:37         ` Eli Zaretskii
2022-09-29 10:05           ` Gerd Möllmann
2022-09-29 10:43             ` Eli Zaretskii
2022-09-29 11:33               ` Gerd Möllmann
2022-09-29 13:10               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-09-29 13:23                 ` Eli Zaretskii
2022-09-29 16:48                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-09-29 13:40                 ` Eli Zaretskii
2022-09-29 14:15                 ` Gerd Möllmann
2022-09-29 14:37                   ` Gerd Möllmann
2022-09-29 22:09                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-09-30  5:28                       ` Gerd Möllmann
2022-09-30  6:11                         ` Eli Zaretskii
2022-09-30 11:31                           ` Gerd Möllmann
2022-09-30 18:29                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-10-02  8:06                               ` Gerd Möllmann
2022-10-06 22:36                           ` Dmitry Gutov
2022-10-07 19:47                             ` Eli Zaretskii
2022-10-08 18:50                               ` Dmitry Gutov
2022-10-10  8:10                                 ` Eli Zaretskii
2022-10-11  2:12                                   ` Dmitry Gutov
2022-10-11  6:37                                     ` Eli Zaretskii
2022-10-11 11:36                                       ` xref-query-replace-in-results error message after xref-find-definitions, was: " Dmitry Gutov
2022-10-11 11:51                                         ` Eli Zaretskii
2022-10-11 12:10                                           ` Dmitry Gutov
2022-10-11 12:17                                             ` Eli Zaretskii
2022-10-11 12:44                                               ` Dmitry Gutov
2022-10-11 12:55                                                 ` Eli Zaretskii
2022-10-11 14:55                                                   ` Dmitry Gutov
2022-10-11 16:01                                                     ` Eli Zaretskii
2022-10-11 16:41                                                       ` Dmitry Gutov
2022-10-11 16:50                                                         ` Eli Zaretskii
2022-10-11 20:31                                                           ` Dmitry Gutov
2022-10-12  5:17                                                             ` Eli Zaretskii
2022-10-12 10:06                                                               ` John Yates
2022-10-12 10:17                                                                 ` Eli Zaretskii
     [not found]                                                                   ` <CAJnXXogKsM=gMTFi2NivDMHW4A3EBtBtsNDBV3o5vcu2xXfuvw@mail.gmail.com>
2022-10-12 13:21                                                                     ` Eli Zaretskii
2022-10-12 16:12                                                                       ` John Yates
2022-10-12 13:47                                                               ` Dmitry Gutov
2022-10-12 14:05                                                                 ` Eli Zaretskii
2022-10-11 14:04                                           ` Stefan Monnier
2022-10-11 14:07                                             ` Stefan Monnier
2022-10-11 15:07                                               ` Dmitry Gutov
2022-10-11 15:37                                             ` Eli Zaretskii
2022-09-30 13:25                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-09-30 14:08                           ` Gerd Möllmann
2022-09-30 15:25                             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-09-30 16:04                               ` Eli Zaretskii
2022-09-30 17:11                                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-10-01  5:06                               ` Gerd Möllmann
2022-10-01 13:54                                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-10-02  8:22                                   ` Gerd Möllmann
2022-10-02 16:32                                     ` Andreas Politz
2022-10-03  4:35                                       ` Gerd Möllmann
2022-10-04 10:50                                         ` Andreas Politz
2022-10-01  7:25                               ` Gerd Möllmann
2022-10-01 10:55                                 ` Gerd Möllmann
2022-10-01 14:01                                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-09-29 16:40                   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-10-01  1:57         ` Richard Stallman
2022-10-01  7:00           ` Eli Zaretskii
2022-10-06 22:26 ` Matt Armstrong
2023-10-06 13:14 ` Gerd Möllmann

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.