Subject: Re: bug#38173: describe-variable: Also tell user *where* variable was changed

From: Phil Sainty <[email-masked]>
Date: Wed, 13 Nov 2019 22:19:25 +1300

On 13/11/19 12:28 PM, 積丹尼 Dan Jacobson wrote:
> Gasp, that var-watcher stuff is so complicated.

Which bit?

If you've unfamiliar with elisp then it possibly seems complicated,
but if/when you learn some more about the language then I think you'll
find that it's a very straightforward piece of code.

The only bit that wasn't directly derived from the documentation at
C-h f add-variable-watcher was the use of `backtrace-frames' (and
pretty-printing that with `pp-to-string').

And the M-x debug-on-variable-change command isn't complicated at
all, and would quite likely show you what you want to see.  You just
need to know debugger command 'c' to continue, 'q' to quit, and the
M-x cancel-debug-on-variable-change command when you're all done.

> How about:
> At the beginning of the user's .emacs:
> (setq tracked-variables LIST_OF_TRACKED_VARIABLES)

Well for specific lists you could do something along the lines
that I suggested, just for all variables in your list.

I'm somewhat inclined to suggest that IF something like this was
done, a global switch would make more sense.

It still might not have the effect you wanted, though -- it's
possible to change the apparent / user-facing value of some variables
without changing the *actual* value of the variable at all.  This is
because of the internal structure of lists in lisp.  A list variable
points at a cons cell, and so long as it remains pointing at a given
cons the variable has the same value; but this doesn't prevent the
list (which is a chain of cons cells) from being altered.  e.g.

(defvar foo '(a b c))
=> foo
foo
=> (a b c)
(debug-on-variable-change 'foo)
=> nil
(setcar foo 'd)
=> d [no debugger was invoked]
foo
=> (d b c)
(setq foo (cdr foo))
Debugger entered--setting foo to (b c):
  (debug--implement-debug-watch foo (b c) set nil)
  (setq foo (cdr foo))
  ...

If you have some reference (maybe even a different variable) pointing
into that list, you can change the list without Emacs ever seeing a
change to the original variable.

(This doesn't always happen, but it certainly *can* happen, and it
might lead to you thinking that the proposed feature wasn't working,
even if it was working as well as it could be expected to.)

I think it's an interesting idea, which would be pretty neat if it
could be made to work; but I don't know if it's practical, and I'm
dubious that it could be comprehensive enough for your liking.

-Phil