TL; DR: when
о побочных эффектах, and
для чистых логических выражений.
Как вы заметили, and
и when
отличаются только в синтаксисе, но в остальном полностью эквивалентны.
Однако синтаксическая разница весьма важна: when
неявная оболочка progn
охватывает все формы, кроме первого. progn
является неотъемлемой обязательной функцией: он оценивает все, кроме самой последней формы тела, только на предмет их побочных эффектов, отбрасывая все возвращенное значение.
Как таковая, when
это также императивная форма: ее главная цель - обернуть побочные формы, потому что только ценность самой последней формы действительно имеет значение для тела.
and
с другой стороны, это чистая функция, основной целью которой является просмотр возвращаемых значений заданных форм аргументов: если вы явно не обернетесь progn
вокруг какого-либо из его аргументов, значение каждой формы аргумента важно, и никакое значение никогда не игнорируется ,
Следовательно, настоящее различие между and
и when
заключается в стилистике: вы используете and
для чисто логических выражений и when
для защиты от побочных эффектов форм.
Следовательно, это плохой стиль:
;; `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)))
И это хорошо
(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)))
Я знаю, что некоторые люди не согласны с этим и радостно используют and
для защиты от побочных эффектов, но я думаю, что это действительно плохой стиль. У нас есть эти различные формы по причине: синтаксис имеет значение . Если бы этого не произошло, мы бы все когда-либо использовали if
, это единственная условная форма, которая вам действительно нужна в Emacs Lisp семантически. Все другие логические и условные формы могут быть записаны в терминах if
.