[Top][All Lists]

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

RE: `save-excursion' defeated by `set-buffer'

From: Drew Adams
Subject: RE: `save-excursion' defeated by `set-buffer'
Date: Sun, 13 Mar 2011 11:23:40 -0700

> > I think it is a little more subtle than that. People may be using it
> > under the expectation that point and mark will also be saved in the
> > buffer accessed by set-buffer.
> wherefrom you assume that?  AFAIU buffer, point and mark are
> stored the very moment `(save-excursion' cames in.
> They should be restored if the parentese closes.
> Every setting of buffer, mark and point between then doesn't 
> matter as far as the buffer now current again is concerned.
> Maybe there have been other `save-excursion' intercurse. But 
> every one tells it's own story.

Exactly.  Andreas is exactly right.  The emperor has no clothes.

> What's the difficulty?

You're right, Andreas - there isn't any.  The doc string of `save-excursion'
says it all, and quite clearly too.

The only possible confusion it lets in, IMO, is via the wording "save...current
buffer" in the first line.  But it then more carefully makes clear that the
buffer _content_ is not _saved_ as in saving to a file; instead, what is "saved"
(remembered) is which buffer is current, and that buffer is made current again
at the end.  And that possible confusion exists just as much - no, more, for the
innocent, praised, and now unduly privileged `save-current-buffer'.

But the issue of that possible confusion has not even been raised by those who
want to warn us about using `save-excursion' with `set-buffer'.  The purported
"problems" they cite have nothing to do with the ambiguous wording about
"saving" the current buffer.

They have to do with users supposedly assuming that `set-buffer' itself saves or
restores state (which buffer is current, or point, or mark) - put differently,
that a `set-buffer' somehow overrides a surrounding `save-excursion', preventing
it from restoring things.  These "problems" have nothing to do with
`save-excursion' or its doc.  If there is any teaching to be done about such
"problems" then it should be done in the doc of `set-buffer'.

On the other hand, Stefan has also claimed that users think that
`save-excursion' will also restore point in other buffers, in particular, in the
`set-buffer' buffers.  Again, the `save-excursion' doc is very clear about this.
If users are confused in this way (no evidence was given) then teach them with
doc, not with blanket warnings that say nothing.

Supposedly people are making these false assumptions all over the place and the
result is buggy code.  Users purportedly think that `save-excursion' does not
restore the point or the mark if there is a `set-buffer' in the body, that the
`set-buffer' takes precedence and any movements after it leave the point or mark
changed beyond the end of the excursion.  Or they purportedly think that
`save-excursion' restores point and mark in more than one buffer.  IOW, users
can't be trusted to read well and code well; they need to be warned.

The variants of the first purported misconception (`set-buffer' overrides
`save-excursion') have to do with whether the target of `set-buffer' is the same
buffer as was saved by `save-excursion'.  Supposedly `save-current-buffer' is
"safer" because it (correctly) leads no one to suppose that point and mark will
be restored.

The mildest variant of this problem is when the user doesn't really want or need
to save and restore point and mark - s?he just wants to restore which buffer is
current.  Stefan says that using `save-excursion' instead of
`save-current-buffer' or `with-current-buffer' is then "inefficient".  Well,
sure, a little bit...  It's (inexpensive) overkill.  But a _warning_?

I have not seen that people are willy-nilly falsely assuming that a `set-buffer'
inside a `save-excursion' overrides it.

I'm sure that a few such bugs have been introduced somewhere, but this kind of
thing can happen also with (let ((a b))...(setq a c)...).  We do not _warn_
people that "`let' defeats `setq'" just because `let' restores a value set by
`setq'.  (Yes, I know the analogy is imperfect; I know there are different `a's
etc.)  We expect users to read the `let' doc and learn to use it correctly.

I also have not seen that people falsely assume that `save-excursion' restores
point for more than the buffer that was current when it was invoked.  Maybe
someone has misunderstood this way, but issue a _warning_ each time
`save-excursion' is used with `set-buffer'?

`save-excursion' simply remembers where you are and returns there when the
excursion is finished.  End of story.  The "where you are" includes the buffer,
your position in that buffer (point), the mark (if any) in that buffer, and
whether the mark was active.

If a non-local exit (e.g. `top-level' or `throw' outside the `save-excursion')
occurs while evaluating the `save-excursion' body then the rest of that body is
not evaluated (naturally).  But the saved information is still restored (which
buffer is current, plus its value of point and mark).  That completes the
behavior of `save-excursion'.  And all of the behavior is explained in the doc

If someone is convinced that `save-excursion' is evil or is too hard for
Emacs-Lisp users to figure out, and s?he wants to teach better programming
practices, the way to do that is not to set off the fire alarm each time code
uses `set-buffer' inside `set-excursion'.

reply via email to

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