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
-~----------~----~----~----~------~----~------~--~---

Reply via email to