Search code examples
macroslispcommon-lispsbcl

In Common Lisp why does the macro OR use a gensym, but not AND?


In Common Lisp (SBCL 1.0.58) why does the macro OR use a gensym, but not AND?

For example,

    CL-USER> (macroexpand '(and 1 2 3 4 5))
    (IF 1
        (AND 2 3 4 5)
        NIL)
    T
    CL-USER> (macroexpand '(or 1 2 3 4 5))
    (LET ((#:G967 1))
      (IF #:G967
          #:G967
          (OR 2 3 4 5)))
    T
    CL-USER> 

I looked at defboot.lisp where the macros are defined but found nothing relevant in the comments.


Solution

  • That's because the implemented logic operators are intended to be short-circuiting and to return the value produced by the last form they evaluated.

    To achieve this, and does not need a gensym because the last form it evaluates will either produce NIL or be the result of the final tail call to itself.

    On the other hand, or has to return the first non-NIL value it evaluates, so it cannot rely on the tail call. It needs a gensym to do that, because without one:

    (IF 1
        1
        (OR 2 3 4 5))
    

    1 appears twice in the expansion, and in our case that means the expression that produces 1 is evaluated twice. And you never want that in your macros.