TL;DR: when
is about side effects, and
is for pure boolean expressions.
As you've noticed, and
and when
differ only in syntax, but are otherwise entirely equivalent.
The syntactic difference is quite important, though: when
wraps an implicit progn
around all but the first argument forms. progn
is an inherently imperative feature: It evaluates all but the very last body form for their side effects only, discarding whatever value they returned.
As such, when
is an imperative form as well: It's main purpose is to wrap side-effecting forms, because only the value of the very last form actually matters for the body.
and
on the other hand is a pure function, whose main purpose is to look at the return values of the given argument forms: Unless you explicitly wrap progn
around any of its arguments, the value of every argument form is important, and no value is ever ignored.
Hence, the real difference between and
and when
is stylistic: You use and
for pure boolean expressions, and when
to put a guard around side-effecting forms.
Hence, these are bad style:
;; `when' used for a pure boolean expression
(let ((use-buffer (when (buffer-live-p buffer)
(file-exists-p (buffer-file-name buffer)))))
...)
;; `and' used as guard around a side-effecting form
(and (buffer-file-name buffer) (write-region nil nil (buffer-file-name buffer)))
And these are good:
(let ((use-buffer (and (buffer-live-p buffer)
(file-exists-p (buffer-file-name buffer)))))
...)
(when (buffer-file-name buffer)
(write-region nil nil (buffer-file-name buffer)))
I know that some people disagree about this, and happily use and
to guard side-effects, but I think that this is really bad style. We have these different forms for a reason: Syntax matters. If it didn't, we'd all only ever use if
, which is the only conditional form you really need in Emacs Lisp semantically. All other boolean and conditional forms can be written in terms of if
.