On Fri, 2008-10-10 at 12:46 -0700, Mike Hinchey wrote: > It's usually advised to avoid eval.
Many thanks Mike. I would like to avoid eval, but I am too stupid. However I would love to find out how to do it. If you could give me hunch I would be more than happy. > See dothread-keeping in > http://github.com/jochu/swank-clojure/tree/master/swank/util/concurrent/thread/thread.clj > And keep-bindings in > http://github.com/jochu/swank-clojure/tree/master/swank/util/util.clj Sweet. The only thing that stops me from using these is that I cannot provide explicitly the values I want to inherit as this would require knowledge of bindings deep down in code that shouldn't care. To elaborate a bit. I have an application running that provides a Repl for maintenance clients over sockets. I started using the Repl example from the Clojure wikibook. However in my running application the expressions evaluated by the Repl trigger forks of new threads which eventually show a result that should be send back to the Repl user over the socket. But as the binding to *out* is not known in these forked threads I will never see anything. If I would need to explicitly say "keep *out*" I would need to do that in application code that forks off the thread and this detail should be of no concern to the application code that also doesn't know about the Repl. So I had to get the list of thread bindings which currently is not exposed in Clojure (and I would be happy if Rich could add that). My next problem with the Repl is, that eval calls Compiler.eval which might also push thread bindings if the ClassLoader is not initialized, effectively hiding the thread bindings established by binding in the Repl code, which forced me to create a class loader before running eval in the Repl. The whole result looks rather messy and I would really like to see Clojure being changed to provide an easy out of the box way to inherit thread locals. Here is the Repl-Code (note the clojure.lang.RT/makeClassLoader call): (defn repl [nspace in out] (clojure.lang.Var/pushThreadBindings {clojure.lang.Compiler/LOADER (clojure.lang.RT/makeClassLoader)}) (binding [clojure/*ns* (or (find-ns nspace) (create-ns nspace)) clojure/*warn-on-reflection* false clojure/*out* (new OutputStreamWriter out) clojure/*err* clojure/*out*] (let [eof (new Object) r (new LineNumberingPushbackReader (new InputStreamReader in))] (println "Welcome User.") (print (ns-name *ns*) "\b=> ") (flush) (loop [e (read r false eof)] (when-not (= e eof) (try (prn (eval e)) (catch Exception e (.printStackTrace e))) (print (ns-name *ns*) "\b=> ") (flush) (recur (read r false eof)))))) (clojure.lang.Var/popThreadBindings)) In the running Repl I will do things like: app.maintenance=> (client! :connect "localhost" 8000) which invokes a connect method which forkes off a thread to read from the connection and print it out. Using on-thread: (defn bindings [] (reduce (fn [env [n v]] (conj env n (var-get v))) [] (clojure.lang.Var/getThreadBindings))) (defmacro on-thread ([f] `(let [env# (bindings)] (eval `(on-thread ~env# ~~f)))) ([env f] `(doto (new Thread #(binding ~env (~f))) (start)))) "bindings" depends on the newly introduced Var.getThreadBindings() method I posted last time. Again I don't like the eval there but I was not able to get it working without it. If I am completely off track here I would be grateful for corrections. The only requirement I have is that my app code should not need to say "keep just these bindings". Thanks for reading this far ;-) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---