Search code examples
macrosclojurequoting

Why can't you unquote-splice in normal (unquoted) code?


In Clojure you can unquote-splice a list of values to generate code, e.g.

(def extra-values [1 2 3 4])

`(+ 100 200 ~@extra-values)
=> (clojure.core/+ 100 200 1 2 3 4)

It seems logical that the same approach should work in an unquoted context, e.g.

(def extra-values [1 2 3 4])

(+ 1000 ~@extra-values)
=> [an error, but one could argue that the answer should be 1010??]

Is there any deep technical/philosphical reason why this can't work?


Solution

  • One simple reason is that then

    `(+ 100 200 ~@extra-values) 
    

    would be poorly defined: does it expand to

    (+ 100 200 1 2 3 4)
    

    or to

    (+ 100 200 ~@extra-values)
    

    ? Both are valid interpretations if the ~@ construct is legal in that context.

    It also causes serious issues in the macro system. Consider

    (defmacro foo [x & args]
      `(list ~x ~(count args)))
    
    (let [data '(1 2 3)]
      (foo "three" ~@data))
    

    How can foo know what args it is being passed? It certainly can't expand that at compile-time, so now unquote-splicing is only valid in some non-quoted contexts.

    And overall it's just muddying up the language to accommodate for poor understanding of core concepts - if you really want to unquote-splice to build a complicated argument list, you can easily use apply in something like

    (apply + `(100 ~@extra-values 200))