Adding -var-missing to Clojure Namespace

Sat 27 October 2012
  • 手艺 tags:
  • clojure published: true comments: true

Motivation

I Just need some mechanism like "methondMissing" in Ruby. When a nonexistent var is called, the lookup system will try to call a "-var-missing" function in the namespace. This function should return a var and clojure compiler assumes this var as the one it was looking for.

For example, in the shake library:
[cc lang="clojure"]
(ns shake.core)

(defn -var-missing [sym]
(create-executable-var sym))
[/cc]

To support lazy loading, shake 0.3.0 won't read your path. It will now create vars on demand. So on calling sh/uname, a var named `uname` will be created. And to create a var, just use intern or eval.

[cc lang="clojure"]
(require '[shake.core :as sh])
(sh/uname -a)
[/cc]

How to

I'm sorry there is no way to implement this except hacking into Clojure's compiler. Fortunately, it's not too difficult to find out the injection point.

As you may know, there are two phases in Clojure compiler: expanding macros and evaluating forms. Both phases will look up vars to find macros or values. So we should take care both of them.

All code diff is here:

Conclusion

Adding -var-missing is just an attempt to implement lazy loading of vars. And it provides another smooth syntax for writing DSLs. But actually, Clojure's macro system provides a great metaprogramming mechanism. So in most case, you don't have to hack into the Compiler like this. Just put your DSL into a top level macro, and you can get them done all in clojure scripts.