Syntax-Quote Alias Resolution

April 23, 2016

This is a short technical note on a new capability that landed in ClojureScript.

Currently in ClojureScript, if you use syntax-quote on a symbol that is qualified with an alias, resolution does not occur:

cljs.user=> (require '[clojure.string :as string])
nil
cljs.user=> `string/reverse
string/reverse

But, with the change for CLJS-1612, this properly reflects the behavior you'd see in Clojure:

cljs.user=> `string/reverse
clojure.string/reverse

Thomas Jack gets credit for the fix—in this case, a nice change to a line in the compiler does the trick.

You might be asking, what does this get us?




Well, since syntax quote is often used in macros, this issue hasn't really caused much of a problem in the past. Consider a macro namespace like this one:

(ns foo.core
  (:require [clojure.string :as string]))

(defmacro reverse-capitalize
  [s]
  `(-> ~s
    string/reverse
    string/capitalize))

If you put the above in a .clj file and use it from JVM ClojureScript, things will work fine, with

(reverse-capitalize "clojurescript")

yielding "Tpircserujolc".

But... things won't pan out so well with bootstrap ClojureScript, where macro namespaces are compiled as ClojureScript. In bootstrap, if you

(macroexpand 
  '(reverse-capitalize 
    "clojurescript"))

you will get

(string/capitalize 
  (string/reverse 
    "clojurescript"))

which won't work (unless you have string aliased to clojure.string in the namespace you are expanding into—but relying on something like that would defeat the entire purpose of syntax quote).

With the patch in place, the above macro expands to

(clojure.string/capitalize 
  (clojure.string/reverse 
    "clojurescript"))

and thus works perfectly well in bootstrap environments like Planck.

Tags: ClojureScript Bootstrap