18

This is a follow-up on the comments on this answer. The following bits of code seem to be equivalent:

(and a b)

(when a b)

Of course and lets you put more conditions: (and a b c d) means (when (and a b c) d)

I tend to use when only to express branching. Are there actual differences? Is it better to use one or the other?

I don't have Emacs' C source at hand; and is a C function; when is a macro that expands to if, which itself is a C function.

1
  • "Of course and lets" should be "Of course `and` lets", but that's only a 2 character change and isn't an allowed edit. There's no override.
    – Harvey
    Commented Aug 13, 2015 at 14:25

3 Answers 3

20

TL;DR: when is about side effects, and is for pure boolean expressions.

As you've noticed, and and when differ only in syntax, but are otherwise entirely equivalent.

The syntactic difference is quite important, though: when wraps an implicit progn around all but the first argument forms. progn is an inherently imperative feature: It evaluates all but the very last body form for their side effects only, discarding whatever value they returned.

As such, when is an imperative form as well: It's main purpose is to wrap side-effecting forms, because only the value of the very last form actually matters for the body.

and on the other hand is a pure function, whose main purpose is to look at the return values of the given argument forms: Unless you explicitly wrap progn around any of its arguments, the value of every argument form is important, and no value is ever ignored.

Hence, the real difference between and and when is stylistic: You use and for pure boolean expressions, and when to put a guard around side-effecting forms.

Hence, these are bad style:

;; `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)))

And these are good:

(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)))

I know that some people disagree about this, and happily use and to guard side-effects, but I think that this is really bad style. We have these different forms for a reason: Syntax matters. If it didn't, we'd all only ever use if, which is the only conditional form you really need in Emacs Lisp semantically. All other boolean and conditional forms can be written in terms of if.

11
  • 2
    IMO (i.e., in the style I use), and is about caring about the return value. It is not necessarily not about using side effects. If my program cares about the return value then I use and. If it does not then I use when. IOW, I use when only for side effects, but I might well use a progn in one of the args to and. It's about whether the return value matters, not about whether it alone matters.
    – Drew
    Commented Jul 23, 2015 at 21:39
  • 5
    and is not a function in any Lisp I know of. In Emacs Lisp it's a special form, in Common Lisp it's a macro, simply because it's expected to have short-circuit behavior (impossible to achieve with functions, because they always evaluate their arguments). Commented Jul 24, 2015 at 9:10
  • 2
    @lunaryorn, Yes, it's not really relevant, but it's true, so I think it's incorrect to write that and is a function, when it's not. It doesn't matter how relevant the fact is to the question, we should always use correct terms, that's all. Commented Jul 24, 2015 at 9:20
  • 2
    Well, I don't think “the value of every argument form is important” is consistent with what that interpretation. It could have been better expressed by saying that no form is evaluated only to have its value thrown away. Commented Jul 24, 2015 at 11:18
  • 3
    Somewhat OT, but: The difference is more than stylistic in Lisps that don't pun nil to mean all of "false", "the empty list", "void", etc. For example in Scheme and Racket the non-truthy result of when is void (i.e. "no meaning") whereas for and it is #f ("false"). Although this is N/A for Elisp, it's something a Lisp generalist might consider. Commented Aug 14, 2015 at 18:58
6

Let me start off by saying that (and a b) and (when a b) in your example do the same thing: First a is evaluated. b is evaluated if a is true#.

But and and when are used for different things.

  • You would use (and a b) to return true# if BOTH a and b are true# (or non-nil); and nil otherwise.

  • You would use (when a b) or to be more correct,

    (when a
       ;; do something like b
       )
    

    when you want the "b" code to execute if and only if a is true#.


Here is an example where you use when and and together:

(when (and a b)
   (do-c))

Above, the function do-c is called ONLY if BOTH a and b are true#.


References for study

# All references to true refer to the Boolean TRUE.

7
  • 4
    and doesn't return t if all its arguments are non-nil, but the value of the last argument. Commented Jul 23, 2015 at 17:37
  • 1
    By t, I meant the Boolean TRUE or non-nil. Thanks, I will clarify that in my answer. Commented Jul 23, 2015 at 17:41
  • I don't think your answer goes much further that what I already stated in the question; I know what both do, and the final example you give already appears in my question ((when (and a b) c)). In addition, the part about how and and when suggests that that's actually how they are used in general, but the very basis for this question was the fact that I often see them used differently (see for example the answer I linked to in my question).
    – Clément
    Commented Jul 23, 2015 at 21:18
  • From a purely functional construct point-of-view, when is for non-terminating evaluations and and is for direct symbols and boolean logic. Functional programming needs this distinction; imperative programming fudge this away.
    – Emacs User
    Commented Jul 23, 2015 at 23:25
  • 1
    I don't think "boolean true" is more clear than just "true".
    – YoungFrog
    Commented Jul 24, 2015 at 5:57
1

@Tarsius's answer is almost right, but not quite.

The convention is that the return value of and and or matters. When you see and or or in code that follows the convention then this is a signal that their return value is used.

That does not mean that they are or they need to be pure functions (perform no side effects). Any of their steps (sexps) can perform side effects.

It's just that the return values of their constituent sexps matter, in these two ways:

  • The return value of each sexp other than the last determines whether subsequent sexps are evaluated. In this regard only whether the value is nil or non-nil matters.

  • The return value any of the sexps can be the return value of the entire and or or, and that value matters (to surrounding code). It need not be Boolean nil or t, and it need not be handled by the surrounding code as a Lisp Boolean value (nil or non-nil). It can be anything at all.

What's important is only that when you see and or or then you can expect that the return value is used somewhere; nothing more.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.