Endless Parentheses

Concise ramblings on Emacs productivity.

The ins and outs of setf

Common-Lisp in Emacs post series

setf is a modest name for a macro that does much more work than it gets paid for. Quoting the doc page:

This is a generalized version of `setq'; the PLACEs may be symbolic
references such as (car x) or (aref x i), as well as plain symbols.
For example, (setf (cadr x) y) is equivalent to (setcar (cdr x) y).
The return value is the last VAL in the list.

Upon reading that, you'd be excused for thinking something mediocre such as “That's neat!” or “I'll try to remember that”. That understatement of a doc page merely touches on the power that lies beneath the surface.

Let's start with an example from the manual, depending on your Emacs version you may need to (require 'cl) first.

(let ((world "world"))
  (setf (substring world 2 4) "o"))
;; world is now "wood"

Now say you want to replace the entire contents of a buffer, instead of the manual erase-buffer then insert, you could do

(setf (buffer-string) "replacement")

Let's get slightly more practical. Do you know which function changes the buffer being displayed by a given window? How about changing the height of a window? You don't need to!

(setf (window-buffer given-window) (get-buffer "*scratch*"))
(setf (window-height) 10)

And finally, if we just want to get cute,

(setf (mark) 10
      (point) 20)

For a wider list, have a look at cl package manual page, which lists what you get by requiring cl or cl-lib, or see the elisp manual page, which lists what's loaded by default on recent versions of Emacs. My thanks to Christopher Wellons and Rob Thorpe for the links, and it was Wellons' post on string mutability which inspired this post.

Tags: lisp, emacs

Say thanks on Gratipay
comments powered by Disqus