Today I ran into a frustrating syntax pitfall in Clojure, which I am attempting to learn using a simple homework assignment as motivation. Below is a simplified testcase containing the same mistake I had in my actual code. The code compiles, but at runtime I receive "java.lang.IllegalStateException: Var selfr is unbound.".
(defn magic  (println "magic happens") ; one too few closing parens (defn selfr [i] (if (< i 0) 0 [(selfr (dec i)) (selfr (dec i))]))) ; one too many closing parens (defn selfr-caller  (selfr 3)) (defn -main [& args] ; (magic) ; uncomment to make everything work (println (selfr-caller)))
If you stare at the code for a bit, you'll see that
selfr is defined inside the
magic function. So why doesn't the compiler complain that
selfr-caller can't see it? What I didn't realize until today (with the help of some wonderful people on IRC) was that
defn hoists the declaration to the top-level, where everything can see it... but the assignment won't occur until the code block is actually run.
This kind of bug is extraordinarily tricky to find, since it is ultimately a syntax error but may not show symptoms depending on the execution order of the code. I suppose this could have been prevented by having a better editor, such as one with draconian indentation support (e.g. Emacs) or perhaps a matching-paren highlighting feature.