Clojure: The subtle difference between quote (‘) and backtick (`)

I’ve written an ebook about Programming Language Concepts      Show me!

The code presented here is available on github .

The obvious parts

You’ll be aware of these if you’ve ever bothered writing macros:

  • Both prevent evaluation of the subsequent expression:
    `(1 2 3) ;; => (1 2 3)
    '(1 2 3) ;; => (1 2 3)
    
  • Backtick allows you to unquote parts of the expression:
    (def x 3)
    `(1 2 ~x) ;; => (1 2 3)
    '(1 2 ~x) ;; => (1 2 (clojure.core/unquote x))
    

    As you can see, quote does not interpret the tilde character (which is just a reader macro for clojure.core/unquote).

  • …or even additionally splice a sequence:
    (def y (list 3 4))
    `(1 2 ~@y) ;; => (1 2 3 4)
    '(1 2 ~@y) ;; => (1 2 (clojure.core/unquote-splicing y))
    

    Same thing here – quote does not do anything with the “~@” reader macro, as it is just an alias for clojure.core/unquote-splicing.

The subtle part

  • However, quote and backtick show different behavior in how they handle namespace resolution for the symbols they quote:
    (def z 111)
    `(1 2 z) ;; => (1 2 user/z)
    '(1 2 z) ;; => (1 2 z)
    

    So why is this relevant?

    Well, consider the following code. The essence of this is that we have a namespace macro-ns in which macros get defined. Those macros are being used in another namespace (user here):

    (in-ns 'macro-ns)
    (clojure.core/use 'clojure.core)
    
    (def z 222)
    
    (defmacro m-quote []
      'z)
    (defmacro m-backtick []
      `z)
    
    ;; Now, we'll want to use these macros in the "user" namespace:
    
    (in-ns 'user)
    
    (def z 111)
    
    (macroexpand-1 '(macro-ns/m-quote))    ;; => z
    (macroexpand-1 '(macro-ns/m-backtick)) ;; => macro-ns/z
    
    (macro-ns/m-quote)    ;; => 111
    (macro-ns/m-backtick) ;; => 222
    

    So obviously it does matter whether you use quote or backtick in a macro, even if you don’t intend to use any unquoting within. As you can see above, m-quote refers to user/z, while m-backtick results in an expansion that uses macro-ns/z.

Leave a Reply

Your email address will not be published. Required fields are marked *

*