1
  (declare ^:dynamic symbol-table)
  (defn answer []
    (prn "blah")
    (binding [symbol-table {:answer 42}]
      (-> "[:h1 (:answer symbol-table)]" read-string eval)))

The above code runs as expected when executed at the repl. it returns

cpress.hsp> (answer)
"blah"                                                                                                                                                                                      
[:h1 42]

However, when it is executed in a thread spawn by http-kit, I get an unable to resolve symbol

Exception in thread "Thread-43" 
java.lang.RuntimeException: Unable to resolve symbol: symbol-table in this context, compiling:(NO_SOURCE_PATH:0:0)
        at clojure.lang.Compiler.analyze(Compiler.java:6792)
        at clojure.lang.Compiler.analyze(Compiler.java:6729)
        at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3874)
        at clojure.lang.Compiler.analyzeSeq(Compiler.java:7005)
        at clojure.lang.Compiler.analyze(Compiler.java:6773)

to simulate this at the repl spawn a thread to run the answer function

  (.. (Thread. answer) start)

Why does this happen and how to fix it?

Some experimentation shows that it can't find the symbol due to namespace. for example, instead of getting the expression from read-string, i put in a literal

  (defn answer2 []
    (binding [symbol-table {:answer 42}]
      (prn (eval `[:h1 (:answer symbol-table)])) ;;works                                                                                                                                    
      ;;(eval '[:h1 (:answer symbol-table)]) ;; does not works                                                                                                                              
      ))

the first eval uses syntax quoting which works, but when i use regular quoting it doesn't work. syntax quoting resolves namespace while regular quoting does not. if read-string returned an expression with namespace qualified symbols then it would solve my problem I think, but read-string does not

1 Answer 1

3

When you run eval, unqualified symbols in the form are resolved in the current namespace at runtime (not that of the namespace where the function is defined).

To solve this, you can create a version of eval with the namespace bound to the one you need:

(defn local-eval [x]
  (binding [*ns* (find-ns 'my-namespace)]
    (eval x)))

(Obviously you need to change my-namespace to reflect the right name). Then you use that instead:

(defn answer []
  (binding [symbol-table {:answer 42}]
    (-> "[:h1 (:answer symbol-table)]" read-string local-eval)))
Sign up to request clarification or add additional context in comments.

3 Comments

this works but what if I don't know the namespace? eval should take an environment map from which it can resolves symbols.
Since you're defining the var, you must know where it's defined, no?
yeah, but the context is I have hiccup stored in a file that contains expressions and values which should use the symbol table to resolve. the person calling eval should not need to specify the namespace their symbol table is located. it makes the api ugly. for example, I would like to call (eval-hiccup (read-string a-file) {:answer 42, age: 10000000}). Passing in the namespace as a key in the symbol-table should work but it makes the api hacky

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.