[Top][All Lists]

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

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

From: Uday S Reddy
Subject: RE: `save-excursion' defeated by `set-buffer'
Date: Mon, 14 Mar 2011 14:20:58 +0000

Well, this discussion has gone haywire.  So, I would like to focus on
this example and leave out all the other shrubbery, hoping that this
might clarify the issue.  I am rewriting the text surrounding the
example, based on your questions.

This `my-beautiful-function' was designed to be called in a buffer A.

(defun my-beautiful-function ()
       (set-buffer B)
       (goto-char x)
       (setq a (find-something))

(defun find-something ()
              (set-buffer A)  
              (goto-char y)

The assumption is that find-something is *buggy* here.  It is moving
point in buffer A though it wasn't supposed to.  (That is why I named
it "find-something" rather than "do-something" or "go-somewhere".)

The `save-excursion' at the outer level in `my-beautiful-function' was
presumably placed there to restore the current buffer.  Just looking
at its body, we don't see any point movements in buffer A.  So, we
might feel justified in thinking that the `save-excursion' can be
replaced by `save-current-buffer'.  But let us leave that aside for
the moment.

As long as you use `my-beautiful-function' in buffer A, it will appear
to work fine, because the unprotected point movement in
`find-something' is cancelled by the `save-excursion' at the
top-level.  If you call it in some other buffer C, it will
unexpectedly move point in buffer A.

My position is that `find-something' is *inherently buggy* because of
its unprotected point movement in buffer A.  The fact that it appears
to work fine as long as it is called from `my-beautiful-function'
invoked in buffer A, doesn't make it right.

The `save-excursion' at the top-level of `my-beautiful-function'
serves to cover up the bug, whether intentionally or unintentionally.  

The solution is to change the `save-excursion' to
`save-current-buffer', exposing the bug, and then to track it down.

> Tell us more.  What buffer is `m-b-f' called in?  Presumably, if it
> is intended to be called in buffer A, then it wants to restore point
> in A when it is done (assuming the `save-excursion' is the last
> thing it does).

Why do you think m-b-f "wants" to restore point in A, and not in other
buffers?  What makes the buffer A special?  Why is it that you should
always restore the point in the current buffer and leave all the other
buffers to their fate?

> Presumably, if it is intended instead to be called in buffer C then
> it wants to restore point in C when it is done.  In this case,
> presumably (if we don't just assume that it is buggy)
> `find-something' wants to leave point in A at Y (assuming it doesn't
> move it in the last `...').

It may not may have been intended to be called in buffer C, but
nothing in the design might indicate that it is intended to be called
only in buffer A.  So, you would be justified in calling it in
another buffer.

> There is no way to know from your skeleton what the purpose or the
> behavior is.  The devil is in the details...which are missing.

So, how much detail would one need to see before one can infer basic
facts about point movements and buffer changes?  

> There is nothing intrinsically wrong with a function that moves point to some
> position in some buffer and leaves it there.  I probably wouldn't name such a
> function just `find-something', however, and I would document that part of its
> purpose is to move point in buffer A or whatever.  Assuming that is the case.

I am sure you you would word things better.  But we live in a free
software world where lots of people contribute code.  The wording may
not be clear, the names may not be clear, and there may be no docs
whatsoever.  You have to infer what you want to infer by looking at
the code.

> > However, my-beautiful-function works fine as
> > long as I call it in buffer A because the "harmlessly redundant"
> > save-excursion at its top-level restores A's point.
> Oh, so you were presuming that `m-b-f' wants to restore A's point.
> OK.  Where's the problem?  (So far nothing is _redundant_, however.)

I have no idea what it means for m-b-f "wanting" to restore A's point.
I don't see why it should care about the buffer A at all.  The way I
view things, m-b-f should restore whatever temporary point movements
it makes.  It shouldn't be covering up the bugs in other functions
like `find-something'.  But the way the save-excursion/set-buffer
combination works, everything is covering up everything else's bugs.
The code might be completely infested with bugs.  But we will never
know, because it is also constantly covering them up!

> Or if by hypothesis `f-s' is buggy and should not in fact move point
> in A, then you should be able to see by debugging that it in fact
> does move point in A, even when `m-b-f' is called in A.  And you
> should be able to tell just by looking at the code that it moves
> point in A.
> I don't deny that if the overall code is complex such a bug might
> not be obvious, but I submit that this is a general problem that has
> nothing special to do with `save-excursion' or `set-buffer'.  It is
> simply about keeping track of the side effects performed by your
> code.
> `find-something' as written has the side effect of moving point in
> buffer A - always.  If that is not the intention, then yes, its bug
> will not surface as long as it is called inside a `save-excursion'
> for buffer A.

Great, I seem to have hit a home run.  `find-something' bug will not
surface as long as it is called inside a `save-excursion' for buffer
A.  You said it!

Now, what plausible reason is there for m-b-f to use `save-excursion'
if not for covering up the `find-something' bug?  If the bug wasn't
there, we can simply convert `save-excursion' to `save-current-buffer'
and we will be fine.

My belief is that all save-excursions used with set-buffer are
precisely there to cover up bugs.  If there is any other conceivable
reason why `save-excursion' should be used with `set-buffer', then
please show me!


reply via email to

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