TL; DR: when
dotyczy efektów ubocznych, and
służy wyłącznie do wyrażeń boolowskich.
Jak zauważyłeś and
i when
różnią się tylko składnią, ale poza tym są całkowicie równoważne.
Różnica składniowa jest jednak dość ważna: when
obejmuje niejawne podejście progn
wokół wszystkich form argumentów oprócz pierwszego. progn
jest z natury imperatywną cechą: ocenia wszystkie formy ciała oprócz ostatniej pod kątem ich skutków ubocznych, odrzucając jakąkolwiek wartość, którą zwrócili.
Jako taka when
jest również formą imperatywną: jej głównym celem jest owijanie form wywołujących skutki uboczne, ponieważ tylko wartość ostatniej formy ma znaczenie dla ciała.
and
z drugiej strony jest funkcją czystą, której głównym celem jest przyjrzenie się wartościom zwrotnym podanych form argumentów: chyba że jawnie obejdziesz progn
którykolwiek z jego argumentów, wartość każdej formy argumentu jest ważna i żadna wartość nigdy nie jest ignorowana .
Stąd prawdziwa różnica między stylistyczną and
i when
stylistyczną: używasz and
do wyrażeń czysto boolowskich i when
strzeżesz form ubocznych.
Dlatego są to zły styl:
;; `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)))
A te są dobre:
(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)))
Wiem, że niektórzy nie zgadzają się z tym i chętnie używają and
do ochrony przed efektami ubocznymi, ale myślę, że to naprawdę zły styl. Mamy różne formy z jednego powodu: Składnia ma znaczenie . Gdyby tak nie było, wszyscy użylibyśmy tylko if
tej jedynej warunkowej formy, której naprawdę potrzebujesz semantycznie w Emacs Lisp. Wszystkie inne formy logiczne i warunkowe można zapisać w kategoriach if
.