Ontem fui surpreendido de repente pela pergunta “Por que a palavra clojure” quando “é implementado como uma macro?”. Por que Rich não poderia escrever algo assim:
(defn when [test & body]
(if test (last body)))
em vez da implementação atual:
(defmacro when
"Evaluates test. If logical true, evaluates body in an implicit do."
{:added "1.0"}
[test & body]
(list 'if test (cons 'do body)))
Gastei vários minutos pensando e cheguei a uma conclusão. A única razão é que os argumentos passados para a macro não são avaliados. Eles são passados para macro apenas como listas. Então aqui está a grande diferença:
(clojure.core/when false (println "123") (+ 3 5))
-> nil
; my dumb implementation
(user/when false (println "123") (+ 3 5))
-> 123
nil
Portanto, a diferença é que todos os argumentos estão sendo avaliados apenas se a condição for verdadeira. Ele limpa seu código de efeitos colaterais e acho que é realmente um comportamento correto.
Existem outros motivos para usar macro neste caso?