Using eval outside the repl -- unbound Compiler.LOADER thread-local

8 views
Skip to first unread message

Chas Emerick

unread,
Jan 3, 2008, 10:31:24 PM1/3/08
to Clojure
I ran into an odd exception when attempting to eval some simple code
in a new Thread:

clojure.lang.Compiler$CompilerException: null:0: Var null is unbound.
at clojure.lang.Compiler.analyzeSeq(Compiler.java:2874)
at clojure.lang.Compiler.analyze(Compiler.java:2820)
at clojure.lang.Compiler.analyze(Compiler.java:2799)
at clojure.lang.Compiler.eval(Compiler.java:2886)
at clojure.eval.invoke(boot.clj:628)
at therapy_remote.serve_connection$fn__288.invoke(server.clj:62)
at clojure.lang.AFn.call(AFn.java:31)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:269)
at java.util.concurrent.FutureTask.run(FutureTask.java:123)
at java.util.concurrent.ThreadPoolExecutor
$Worker.runTask(ThreadPoolExecutor.java:650)
at java.util.concurrent.ThreadPoolExecutor
$Worker.run(ThreadPoolExecutor.java:675)
at java.lang.Thread.run(Thread.java:613)
Caused by: java.lang.IllegalStateException: Var null is unbound.
at clojure.lang.Var.get(Var.java:129)
at clojure.lang.Compiler$QuoteExpr.<init>(Compiler.java:994)
at clojure.lang.Compiler$QuoteExpr$Parser.parse(Compiler.java:1040)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:2867)

The above was thrown when (eval '(1 2 3)) was called in a new Thread.
I ran things through a debugger, and the problem ended up being that
the clojure.lang.Compiler.LOADER var's value was null in the new
thread context. Looking at what Repl does to set up the thread
locals, I now execute this in every new thread I create where I'm
evaling code:

(. clojure.lang.Var (pushThreadBindings {(. clojure.lang.Compiler
LOADER) (new clojure.lang.DynamicClassLoader)}))

I don't mind this, but it seems that this sort of setup (which is
duplicated in the Repl, implementations of load and load-file, etc)
should happen automatically and lazily. Alternatively, a first easy
step would be to have a thread-setup function in the std lib that took
care of such things.

Cheers,

- Chas

Rich Hickey

unread,
Jan 4, 2008, 8:33:54 AM1/4/08
to Clojure


On Jan 3, 10:31 pm, Chas Emerick <cemer...@snowtide.com> wrote:
> I ran into an odd exception when attempting to eval some simple code
> in a new Thread:
>
> clojure.lang.Compiler$CompilerException: null:0: Var null is unbound.

> The above was thrown when (eval '(1 2 3)) was called in a new Thread.
> I ran things through a debugger, and the problem ended up being that
> the clojure.lang.Compiler.LOADER var's value was null in the new
> thread context. Looking at what Repl does to set up the thread
> locals, I now execute this in every new thread I create where I'm
> evaling code:
>
> (. clojure.lang.Var (pushThreadBindings {(. clojure.lang.Compiler
> LOADER) (new clojure.lang.DynamicClassLoader)}))
>
> I don't mind this, but it seems that this sort of setup (which is
> duplicated in the Repl, implementations of load and load-file, etc)
> should happen automatically and lazily. Alternatively, a first easy
> step would be to have a thread-setup function in the std lib that took
> care of such things.
>

It's not that straightforward. First off, because it is a paired push/
pop operation, it's not equivalent to a lazy initialization. Second,
different apps might have different policies re: the retention of the
classloader. Third, it's more of a general problem than just LOADER/
IMPORTS/REFERS etc - when creating a new thread an app must decide
what the dynamic context will be and establish bindings for any vars
it wants the thread to see.

Part of the nuisance of this, and the source of repetition of all
patterns that require matched operation, is that Java doesn't have
closures, so you can't do stuff like:

inMyStandardEvalContext(doSomething)

without wrapping doSomething in a Runnable/Callable/IFn.

Obviously it's easy in Clojure.

In any case, LOADER is still an implementation detail, so I've made it
so that Compiler.eval will set it up (and tear it down!) if it is not
otherwise set up when eval is called.

Rich
Reply all
Reply to author
Forward
0 new messages