problem with resolve

7 views
Skip to first unread message

kony

unread,
Nov 24, 2009, 6:01:24 AM11/24/09
to Clojure
Hi,

I found that resolve does not work correctly (I guess) when it is
called from other thread than main:

e.g.

let define

(def zz 123)

and afterwords call:

(.start (new Thread #(println (resolve 'zz))))

for me it does not work (it returns nil)

Workaround is to write a kind of "super-resolve" that search the all
available namespaces:

(defn super-resolve [sym-exp]
(loop [all-namespaces (all-ns) ]
(let [current-namespace (first all-namespaces)]
(let [result (ns-resolve current-namespace sym-exp)]
(if (and (= result nil) (> (count all-namespaces) 1))
(recur (rest all-namespaces))
result)))))

and now is OK:

(.start (new Thread #(println (super-resolve 'zz))))

The question is, however, whether the resolve shouldn't work in the
same manner as resolve?
What do you think?

Christophe Grand

unread,
Nov 24, 2009, 11:31:44 AM11/24/09
to clo...@googlegroups.com
On Tue, Nov 24, 2009 at 12:01 PM, kony <kulak...@gmail.com> wrote:
Hi,

I found that resolve does not work correctly (I guess) when it is
called from other thread than main:

e.g.

let define

(def zz 123)

and afterwords call:

(.start (new Thread #(println (resolve 'zz))))

for me it does not work (it returns nil)


This is because the spawned thread isn't in the current namespace:
user=> (.start (Thread. #(println *ns*)))
nil
#<Namespace clojure.core>

So you have to capture a reference to your current ns one way or the other. Some examples:
(.start (let [ns *ns*] (Thread. #(binding [*ns* ns] (println (resolve 'zz))))))
or
(.start (let [ns *ns*] (Thread. #(println (ns-resolve ns 'zz)))))
or
(.start (let [resolve (partial ns-resolve *ns*)] (Thread. #(println (resolve 'zz)))))

Note that if your symbol is namespaced that simply works:
(.start (Thread. #(println (resolve 'user/zz))))
or, simpler:
(.start (Thread. #(println (resolve `zz)))) ; a backquote
 
hthn

Christophe


--
Professional: http://cgrand.net/ (fr)
On Clojure: http://clj-me.cgrand.net/ (en)

John Harrop

unread,
Nov 24, 2009, 11:34:06 AM11/24/09
to clo...@googlegroups.com
On Tue, Nov 24, 2009 at 6:01 AM, kony <kulak...@gmail.com> wrote:
Hi,

I found that resolve does not work correctly (I guess) when it is
called from other thread than main:

e.g.

let define

(def zz 123)

and afterwords call:

(.start (new Thread #(println (resolve 'zz))))

for me it does not work (it returns nil)

Seems to be an issue with *ns*:

sandbox=> *ns*
#<Namespace sandbox>
sandbox=> (.start (new Thread #(println *ns*)))
#<Namespace clojure.core>

It's a dynamic var and I guess clojure.core is the root binding. You'll have to use (in-ns foo) or (binding [*ns* foo] ...) or something to really fix it.

Krukow

unread,
Nov 24, 2009, 11:40:08 AM11/24/09
to Clojure


On Nov 24, 12:01 pm, kony <kulakow...@gmail.com> wrote:
> Hi,
>
> I found that resolve does not work correctly (I guess) when it is
> called from other thread than main:

I guess your new thread also has the root binding for *ns* the current
namespace, which apparently is core
user=> (.start (new Thread #(println *ns*)))
nil
user=> #<Namespace clojure.core>

So you could do this:

user=> (def zz 42)
#'user/zz
user=> (.start (new Thread #(println (ns-resolve 'user 'zz))))
nil
user=> #'user/zz

What is the use case? Or are you just playing around?
/Karl

Krukow

unread,
Nov 24, 2009, 12:07:30 PM11/24/09
to Clojure

Three concurrent replies. We'd be better off using locks :-)

kony

unread,
Nov 24, 2009, 3:45:25 PM11/24/09
to Clojure


On 24 Lis, 18:07, Krukow <karl.kru...@gmail.com> wrote:
> Three concurrent replies. We'd be better off using locks :-)

Three concurrent replies but each of them brings something new ;)
Thank you very much for all of them!

... what is the use case,... I am just working on some kind of process
algebra simulator written in Clojure. Processes have to be interpreted
in the separate threads, so that is why that problem arose.

BTW: another question is whether the behavior of resolve is a feature
or it is rather implementation error. Be honest I do not have opinion
in this matter. To little I know the Clojure.

Krukow

unread,
Nov 25, 2009, 12:47:39 AM11/25/09
to Clojure
It's not an error: vars have a root binding and thread local semantics
(*ns* is root-bound to the clojure.core namespace, and in the repl
thread it is bound to the user namespace). Since you are starting a
new thread that thread sees the root binding.

http://clojure.org/vars

But you usually don't need to use resolve directly:
(If in emacs, make sure you do M-x slime-redirect-inferior-output - if
you don't, you won't see the threads output)

user> (def zz 42)
#'user/zz
user> (.start (Thread. #(println zz)))
42
nil
user> (.start (Thread. #(println (resolve 'zz))))
nil
nil
user> (.start (Thread. #(println (ns-resolve 'user 'zz))))
#'user/zz

Regards,
/Karl
Reply all
Reply to author
Forward
0 new messages