1

In clojure, macros give a tremendous power to the programmer. eval also is very powerful. There exist some subtle differences between the two. I hope that this riddle will shine some light on this topic.

(ns hello)
(defmacro my-eval [x] `~(read-string x))
(defn hello[] "Hello")
(defn run-stuff []
  (println (hello))
  (println (my-eval "(hello)"))
  (println (eval (read-string "(hello)"))))
(ns main)
(try (hello/run-stuff)
  (catch Exception e (println e)))

Over the 3 statements inside run-stuff body, which one causes an exception and why the other ones don't?

I have formulated the following riddle following the investigation of this beautiful question Clojure - (read-string String calling function. Thanks to @Matthias Benkard for the clarifications

Community
  • 1
  • 1
viebel
  • 19,372
  • 10
  • 49
  • 83

1 Answers1

4

(println (hello)) and (println (my-eval "(hello)")) are completely identical statements -- the only difference is that one will confuse your editor more. my-eval is NOT comparable to the real eval. The difference is that the argument to my-eval needs to be a string at compile time -- the following errors out because the symbol x can't be cast to a string.

(def x "(hello)")
(my-eval x)

This makes my-eval utterly pointless - you can "eval" a literal string or you can remove the quotes and the my-eval and have equally functional code (that your editor will understand).

Real eval, on the other hand, tries to compile code at run time. Here, it fails because it is being run from the main namespace, not the hello namespace, as @Matthias Benkard pointed out.

Retief
  • 3,199
  • 17
  • 16