Skip to main content

when, unless

when, unless Macro

Syntax:

when test-form {form}* → {result}*

unless test-form {form}* → {result}*

Arguments and Values:

test-form—a form.

forms—an implicit progn.

results—the values of the forms in a when form if the test-form yields true or in an unless form if the test-form yields false; otherwise nil.

Description:

when and unless allow the execution of forms to be dependent on a single test-form.

In a when form, if the test-form yields true, the forms are evaluated in order from left to right and the values returned by the forms are returned from the when form. Otherwise, if the test-form yields false, the forms are not evaluated, and the when form returns nil.

when, unless

In an unless form, if the test-form yields false, the forms are evaluated in order from left to right and the values returned by the forms are returned from the unless form. Otherwise, if the test-form yields false, the forms are not evaluated, and the unless form returns nil.

Examples:

(when t ’hello) → HELLO 
(unless t ’hello) → NIL
(when nil ’hello) → NIL
(unless nil ’hello) → HELLO
(when t) → NIL
(unless nil) → NIL
(when t (prin1 1) (prin1 2) (prin1 3))
123
3
(unless t (prin1 1) (prin1 2) (prin1 3)) → NIL
(when nil (prin1 1) (prin1 2) (prin1 3)) → NIL
(unless nil (prin1 1) (prin1 2) (prin1 3))
123
3
(let ((x 3))
(list (when (oddp x) (incf x) (list x))
(when (oddp x) (incf x) (list x))
(unless (oddp x) (incf x) (list x))
(unless (oddp x) (incf x) (list x))
(if (oddp x) (incf x) (list x))
(if (oddp x) (incf x) (list x))
(if (not (oddp x)) (incf x) (list x))
(if (not (oddp x)) (incf x) (list x))))
((4) NIL (5) NIL 6 (6) 7 (7))

See Also:

and, cond, if, or

Notes:

(when test {form}+) (and test (progn {form}+))

(when test {form}+) (cond (test {form}+))

(when test {form}+) (if test (progn {form}+) nil)

(when test {form}+) (unless (not test) {form}+)

(unless test {form}+) (cond ((not test) {form}+))

(unless test {form}+) (if test nil (progn {form}+))

(unless test {form}+) (when (not test) {form}+)

Data and Control

Expanded Reference: when, unless

Basic usage of when

when evaluates its body forms only if the test is true, and returns the value of the last body form. If the test is false, it returns NIL without evaluating any body forms.

(when t "hello")
=> "hello"

(when nil "hello")
=> NIL

Basic usage of unless

unless is the opposite of when. It evaluates its body forms only if the test is false.

(unless nil "hello")
=> "hello"

(unless t "hello")
=> NIL

when and unless allow multiple body forms

Unlike if, both when and unless accept multiple body forms (an implicit progn). All forms are evaluated in order and the value of the last is returned.

(when (> 5 3)
(format t "first~%")
(format t "second~%")
"done")
.. first
.. second
..
=> "done"

Using when for one-sided conditionals

when is preferred over if when there is no else branch. It makes the intent clearer.

(defun maybe-print (x)
(when (stringp x)
(format t "Got a string: ~a~%" x)
t))

(maybe-print "hello")
.. Got a string: hello
..
=> T

(maybe-print 42)
=> NIL

Using unless for guard clauses

unless is commonly used for guard clauses and default-value patterns.

(defun safe-divide (a b)
(unless (zerop b)
(/ a b)))

(safe-divide 10 3)
=> 10/3
(safe-divide 10 0)
=> NIL

Side effects and return values

Both when and unless return NIL when they do not execute their body, which makes them useful in conditional side-effect code.

(let ((warnings '()))
(dolist (x '(1 -3 5 -2 0))
(when (minusp x)
(push x warnings)))
warnings)
=> (-2 -3)