WhenToUseIf

This page is about conditional control of program flow (evaluation).

All EmacsLisp control structures are functions (in the broad sense, which includes macros): they return a value. Sometimes you are not interested in this value (that is, it is not used by the calling code).

For more information about conditional expressions, see Conditionals or use ‘C-h f cond’, ‘C-h if’ etc.

When to Use Which Conditional Control Structure?

Which you use is a question of style and succinctness. In general, the following heuristics provide a guide:

     (let ((x (y)))
       (cond ((eq x 'lazy) (do-this))
             ((eq x 'spoiled) (do-that))
             ((eq x 'ignorant) (do-this-and-that))
             ((eq x 'dishonest) (do-something-else))
             ((eq x 'incompetent) (do-so-and-so))
             ((eq x 'z) (do-such-and-such))
             (t (must-be-another-x))))

Cond

If-Then-Else

 (if TEST EVAL-IF-T EVAL-IF-NIL...)

Example:

 (if (>= emacs-major-version 21)                        ; this is the test, the "if"
     (message "You are running Emacs 21!  Lucky you.") ; This is the "then"
   (ding)                                              ; From here on is the "else"
   (message "Time to upgrade, don't you think?"))

If the test is true then a single sexp is evaluated. If the test is false then a (possibly empty) sequence of sexps are evaluated, in order.

Such a sequence of sexps is called an “implicit ‘progn’” in Emacs jargon. For more about implicit ‘progn’s, see Sequencing .

If you want to evaluate multiple sexps when the result is true, then either use ‘cond’ or use an explicit ‘progn’. For example:

 (if (>= emacs-major-version 21)
     (progn ; Lets you evaluate more than one sexp for the true case
         (ding)
         (message "You are running Emacs 21!  Lucky you."))
   (ding)
   (message "Time to upgrade, don't you think?"))

When, Unless

‘when’ and ‘unless’ are equivalent to ‘if’ with a vacuous THEN part. IOW, they let you conditionally evaluate a sequence of sexps (an implicit ‘progn’).

 (when CONDITION EVAL-IF-T...)
 (unless CONDITION EVAL-IF-NIL...)

The former is the same as (if (not CONDITION ) nil EVAL-IF-T...). The latter is the same as (if CONDITION nil EVAL-IF-NIL...).

‘when’ tests whether the CONDITION is true, and if so it evaluates the sexps that follow (an implicit ‘progn’). ‘unless’ does the same, but tests whether the CONDITION is false. For example:

 ; Load my abbreviations and use them in all text modes
 (unless (featurep 'xemacs)
   (add-hook 'text-mode-hook (lambda () (abbrev-mode 1)))
   (read-abbrev-file (expand-file-name "~/.abbrev_defs")))

This tests whether there is a feature called ‘xemacs’. If so, it does nothing. If not, it evaluates the sexps (add-hook....) and (read-abbrev-file...), in that order.

Using ‘when’ and ‘unless’ is a way of signalling to human readers that your code does not use the return value. This is an informal convention, and it is not followed by everyone.

And, Or

Use ‘and’ or ‘or’ when (a) the return value is important (it is used by the calling code) and (b) you want to evaluate sexps in order until one of them returns ‘nil’ (for ‘and’) or non-‘nil’ (for ‘or’).

Example:

    (and (re-search-backward " " nil t)
         (re-search-backward "[^ \n]" nil t)
         (re-search-forward "[ \n]+" nil t)
         (replace-match "-"))

The sexps following ‘and’ are evaluated in order until one of them returns ‘nil’ or until the last one has been evaluated.

In the example, ‘and’ first tests whether there is a space before the current location of point. If so, then it tests the second sexp, and so on. As soon as any condition is false ‘and’ is done and returns ‘nil’ – subsequent conditions are not evaluated.

Case, Ecase

‘case’ and ‘ecase’ are macros that are part of the Common Lisp package. To use either, just require cl at compile time.

‘case’ is like ‘cond’ in that it can involve multiple tests. What distinguishes ‘case’ is that a single test sexp is evaluated only once. The result of that evaluation is compared to multiple values, in turn, until a comparison succeeds or all have been tried. Comparison is done using CommonLisp function ‘eql’.

When a comparison succeeds. its associated sexps are evaluated (an implicit ‘progn’). If none succeeds then ‘case’ returns ‘nil’.

A ‘case’ expression can include a final default clause by using a comparison value of ‘t’ or ‘otherwise’. Comparison values can be grouped, so that several values will lead to the same consequence code being executed.

‘ecase’ is like ‘case’ except it signals error if no test succeeds.

  (defun my-got-what (x)
    (ecase x
      ((nil) :got-nil)
      ((t) :got-t)
      ((foo bar) :got-foo-or-bar)))
  (my-got-what 'nil) ; ⇒ :got-nil
  (my-got-what 'foo) ; ⇒ :got-foo-or-bar

CategoryCode