Search code examples
functionclojurespecial-form

Why is do a special form?


In Clojure, why is do a special form, instead of a function implemented like this?

(defn do [& exprs]
  (last exprs))

Solution

  • Basic sequential execution semantics

    fn (well, fn*) actually reuses the logic behind do, as do other forms with bodies – let*, letfn*, try. Since there are several of these, it makes sense to have them reuse the basic "evaluate expressions in sequence" logic; and since this in itself is useful to user code outside the context of the more complex special form, it makes sense to expose it as do.

    Were fn* the basic special form instead, sequentially evaluating expressions would involve making a function call – the overhead of that would not be acceptable for this sort of low-level facility.

    (On the other hand, replacing the other special forms with macros wrapping their bodies in implicit dos wouldn't introduce any overhead. In the context of the Clojure compiler as it stands, however, it wouldn't be a huge win either – on this point at least it's fairly DRY already.)

    Top-level do

    Additionally, top-level dos are treated specially by the compiler in that

    (do
      (foo)
      (bar))
    

    is equivalent at top level (and only at top level) to

    (foo)
    (bar)
    

    – that is, to the individual expressions written out separately. This allows macros to output (code equivalent to) multiple top-level expressions.

    It wouldn't be impossible to interpret top-level calls to some special function in this way, but using a special form for this purpose is significantly cleaner.