6

Q: is there an alternative to save-excursion that only saves/restores point?

When writing elisp functions, I often need to save point, do some stuff in the current buffer, and then restore point. I had always used save-excursion for doing so, but the docstring notes that it will:

Save point, mark, and current buffer; execute BODY; restore those things. Executes BODY just like progn. The values of point, mark and the current buffer are restored even in case of abnormal exit (throw or error). The state of activation of the mark is also restored.

Now: that seems like overkill if all I care about is point and I'm not touching (or otherwise don't care about) the mark and current buffer. In the absence of something like save-point, I wrote the following macro:

(defmacro save-point (&rest body)
  (cl-declare (debug t) (indent 0))
  (let ((orig (cl-gensym)))
    `(let ((,orig (point-marker)))
       (unwind-protect
           (progn ,@body)
         (goto-char ,orig)))))

save-excursion is written in C, so it wasn't a priori clear that this macro would be faster than the C code despite saving and restoring fewer objects. And, in fact, it's about an order of magnitude slower:

(benchmark-run-compiled 1000
  (save-point t))                   ; => .0005ish

(benchmark-run-compiled 1000
  (save-excursion t))               ; => .00005ish

It currently looks like the macro is a fool's errand. So:

  • Does something like this save-point macro already exist?
  • How could one streamline this macro to speed it up?
  • Is there any way to make up the speed difference between the C code and the elisp code?
  • 4
    Have you run into a situation where save-excursion is noticeably slow? This seems like a lot of effort to optimize away a tiny fraction of a second. Not that your questions aren't generally interesting (+1), but the application seems a bit strained. – Tyler Jun 10 '15 at 15:02
  • @Tyler: not yet, but I've always wondered about the extra overhead for functions that get invoked a lot (eg, something called in post-self-insert-hook). It may turn out to be a red herring, so right now it's a curiosity question. – Dan Jun 10 '15 at 15:08
  • 1
    In Emacs 25, save-excursion no longer saves the mark. – jch Jun 10 '15 at 19:29
4

You can always easily save and restore point yourself, using let and unwind-protect. And you can roll that into your own macro, if you like. But why bother?

There is a reason that these things are saved & restored together by save-excursion. Otherwise, you had better be sure about which buffer you want to restore the value of point for etc.

My advice: use save-excursion. My guess is that it really costs nothing more than what you would code yourself to save & restore just point, and in fact will be quite a bit faster because it is coded in C.

Even if save-excursion were coded in Lisp it would be just two more let bindings, one call to current-buffer, one more setq and a set-buffer.

  • The macro was an attempt to write a let + unwind-protect template, but it appears to be the case that "why bother?" is indeed the practical upshot. – Dan Jun 11 '15 at 14:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.