13

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.

  • "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 Aug 13 '15 at 14:25
17

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.

  • 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 Jul 23 '15 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). – Mark Karpov Jul 24 '15 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. – Mark Karpov Jul 24 '15 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. – Harald Hanche-Olsen Jul 24 '15 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. – Greg Hendershott Aug 14 '15 at 18:58
4

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.

  • 3
    and doesn't return t if all its arguments are non-nil, but the value of the last argument. – Meaningful Username Jul 23 '15 at 17:37
  • 1
    By t, I meant the Boolean TRUE or non-nil. Thanks, I will clarify that in my answer. – Kaushal Modi Jul 23 '15 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 Jul 23 '15 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 Jul 23 '15 at 23:25
  • 1
    I don't think "boolean true" is more clear than just "true". – YoungFrog Jul 24 '15 at 5:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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