Next: Constructs for Combining Conditions, Previous: Sequencing, Up: Control Structures [Contents][Index]
Conditional control structures choose among alternatives. Emacs Lisp
has five conditional forms: if, which is much the same as in
other languages; when and unless, which are variants of
if; cond, which is a generalized case statement;
and pcase, which is a generalization of cond
(see Pattern-Matching Conditional).
if chooses between the then-form and the else-forms
based on the value of condition. If the evaluated condition is
non-nil, then-form is evaluated and the result returned.
Otherwise, the else-forms are evaluated in textual order, and the
value of the last one is returned. (The else part of if is
an example of an implicit progn. See Sequencing.)
If condition has the value nil, and no else-forms are
given, if returns nil.
if is a special form because the branch that is not selected is
never evaluated—it is ignored. Thus, in this example,
true is not printed because print is never called:
(if nil
(print 'true)
'very-false)
⇒ very-false
This is a variant of if where there are no else-forms,
and possibly several then-forms. In particular,
(when condition a b c)
is entirely equivalent to
(if condition (progn a b c) nil)
This is a variant of if where there is no then-form:
(unless condition a b c)
is entirely equivalent to
(if condition nil a b c)
cond chooses among an arbitrary number of alternatives. Each
clause in the cond must be a list. The CAR of this
list is the condition; the remaining elements, if any, the
body-forms. Thus, a clause looks like this:
(condition body-forms…)
cond tries the clauses in textual order, by evaluating the
condition of each clause. If the value of condition is
non-nil, the clause succeeds; then cond evaluates its
body-forms, and returns the value of the last of body-forms.
Any remaining clauses are ignored.
If the value of condition is nil, the clause fails, so
the cond moves on to the following clause, trying its condition.
A clause may also look like this:
(condition)
Then, if condition is non-nil when tested, the cond
form returns the value of condition.
If every condition evaluates to nil, so that every clause
fails, cond returns nil.
The following example has four clauses, which test for the cases where
the value of x is a number, string, buffer and symbol,
respectively:
(cond ((numberp x) x)
((stringp x) x)
((bufferp x)
(setq temporary-hack x) ; multiple body-forms
(buffer-name x)) ; in one clause
((symbolp x) (symbol-value x)))
Often we want to execute the last clause whenever none of the previous
clauses was successful. To do this, we use t as the
condition of the last clause, like this: (t
body-forms). The form t evaluates to t, which is
never nil, so this clause never fails, provided the cond
gets to it at all. For example:
(setq a 5)
(cond ((eq a 'hack) 'foo)
(t "default"))
⇒ "default"
This cond expression returns foo if the value of a
is hack, and returns the string "default" otherwise.
Any conditional construct can be expressed with cond or with
if. Therefore, the choice between them is a matter of style.
For example:
(if a b c) ≡ (cond (a b) (t c))
It can be convenient to bind variables in conjunction with using a
conditional. It’s often the case that you compute a value, and then
want to do something with that value if it’s non-nil. The
straightforward way to do that is to just write, for instance:
(let ((result1 (do-computation)))
(when result1
(let ((result2 (do-more result1)))
(when result2
(do-something result2)))))
Since this is a very common pattern, Emacs provides a number of macros to make this easier and more readable. The above can be written the following way instead:
(when-let* ((result1 (do-computation))
(result2 (do-more result1)))
(do-something result2))
There’s a number of variations on this theme, and they’re briefly described below.
Evaluate each binding in varlist, stopping if a binding value is
nil. If all are non-nil, return the value of
then-form, otherwise the last form in else-forms.
Each element of varlist has the form (symbol value-form): value-form is evaluated and symbol is
locally bound to the result. Bindings are sequential, as in let*
(see Local Variables). As a special case, symbol can be
omitted if only the test result of value-form is of interest:
value-form is evaluated and checked for nil, but its value
is not bound.
Evaluate each binding in varlist, stopping if a binding value is
nil. If all are non-nil, return the value of the last
form in then-forms.
varlist has the same form as in if-let*: Each element of
varlist has the form (symbol value-form),
in which value-form is evaluated and symbol is locally bound
to the result. Bindings are sequential, as in let* (see Local Variables). As a special case, symbol can be omitted if only the
test result of value-form is of interest: value-form is
evaluated and checked for nil, but its value is not bound.
Evaluate each binding in varlist, stopping if a binding value is
nil. If all are non-nil, return the value of the last
form in then-forms, or, if there are no then-forms, return
the value of the last binding.
varlist has the same form as in if-let*: Each element of
varlist has the form (symbol value-form),
in which value-form is evaluated and symbol is locally bound
to the result. Bindings are sequential, as in let* (see Local Variables). As a special case, symbol can be omitted if only the
test result of value-form is of interest: value-form is
evaluated and checked for nil, but its value is not bound.
Some Lisp programmers follow the convention that and and
and-let* are for forms evaluated for return value, and
when and when-let* are for forms evaluated for side-effect
with returned values ignored.
A similar macro exists to run a loop until one binding evaluates to
nil:
Evaluate each binding in spec in turn, stopping if a binding value
is nil. If all are non-nil, execute then-forms,
then repeat the loop. Note that when the loop is repeated, the
value-forms in spec are re-evaluated and the bindings are
established anew.
varlist has the same form as in if-let*: Each element of
varlist has the form (symbol value-form),
in which value-form is evaluated and symbol is locally bound
to the result. Bindings are sequential, as in let* (see Local Variables). As a special case, symbol can be omitted if only the
test result of value-form is of interest: value-form is
evaluated and checked for nil, but its value is not bound.
The return value of while-let is always nil.
Next: Constructs for Combining Conditions, Previous: Sequencing, Up: Control Structures [Contents][Index]