Hum, you're having me question myself. See, I don't think dynamically scoped Vars are intended for anything in particular, they are what they are. Yes, they are useful when you need to pass configuration down a call stack, as long as you make sure you handle the thread-boundaries along the way. They can also be used to share per thread data throughout a thread's execution, which is what ThreadLocal in java does. So basically, I see two use cases. One, you want shared read only data accessible throughout a call stack (for that, they aren't as good as true dynamics, because you'll need to manually handle the thread boundaries). Or you want shared writable state per-thread, making this not per-thread would be dangerous, and can be done if you re-bind it manually across threads or when using constructs that does so like future.
The reason they are made per-thread, and not truly dynamic, as in, taking on the value down the stack no matter what, is because threads could content on it, and it could cause bugs, so its made per-thread for safety. Here's an example of such caveat: (def ^:dynamic *dd*) (binding [*dd* (atom "John")] (let [a (future (reset! *dd* "Bob")) b (future (reset! *dd* "Mike"))] @*dd*)) Run this many times, and *dd*'s value could be either Mike or Bob based on which threads wins the race. So the limitation of dynamic scope are inherent to dynamic scoping where you have threads. Clojure's attempt at solving this limitation is to make them per-thread, with explicit cross thread management through (bound-fn). After a few releases, Clojure decided to make future and a few other constructs implicitly propagate the dynamic var across threads as that was often what people were expecting. All to say, when using dynamic Vars in Clojure, you must be thread aware and understand the caveats. There is no better way that I'm aware of to handle dynamic scope in a multi-threaded environment. Clojure has root bindings, which Java ThreadLocals does not have. Clojure lets you say, if this thread does not have a value for the dynamic Var, fetch the root value instead. This is really useful in the use case of read only data, like configuration, because you can set a default config. You can simulate this in Java with initialValue. Now, the initialValue lets you do one more thing, it can let you generate per-thread values on get, without needing to set it. Such as setting a random int on the first get, and subsequent get from that thread will from then on return that same generated random int. In Clojure, this is what I've seen for such use case: (def ^:dynamic *id*) (defmacro with-id [& body] `(binding [*id* (rand-int 10000)] ~@body)) @(future (with-id (println (str "My request id is: " *id*)) "Success")) It's not as convenient per-say, since you have to be explicit and call the macro from each Thread before getting the value, but it solves the use case. Remember that ThreadLocals are more inconvenient to get though, since you need to get the ThreadLocal and then get the value out of it. So in some ways, Clojure dynamics can also be seen as more convenient. Up to now, I feel like there is nothing I can not do with a Clojure Dynamic Var that I could with a ThreadLocal. They're not identical, but to me, the two fulfills equal use cases. And since under the hood, Clojure dynamic Vars are implemented with ThreadLocal, they should perform similarly too. You say you can pass around references of ThreadLocals, but I'm not sure what the point of that would be, like what use case would it allow? In general, and even the Java doc page says so, you'll put the ThreadLocal in a static variable, i.e., private static final ThreadLocal<Integer> threadId. At that point, it's equal to (def ^:dynamic threadId). Anyways, you can also do that in Clojure, you can pass around the Var such as: (defn printVar [v] (println @v)) (with-local-vars [*threadId* 0] (.start (Thread. (bound-fn [] (var-set *threadId* 1) (printVar *threadId*)))) (.start (Thread. (bound-fn [] (var-set *threadId* 2) (printVar *threadId*))))) I have a function printVar that takes a Var and prints it. Then I create a new Var called *threadId* and I set it to two different values, one for each Thread. I pass the Var to my Var printing function, and as you can see if you run this, it works like it would in Java if you did the same with ThreadLocal, printing different values based on the thread. I hope this helps. On Friday, 3 March 2017 07:02:21 UTC-8, Ernesto Garcia wrote: > > On Sunday, February 26, 2017 at 6:23:28 AM UTC+1, Didier wrote: >> >> Dynamic scoping and Java ThreadLocals gives you equal functionality, so >> I'd use them equally. This is because Clojure supports thread bound dynamic >> scope. >> > > I wouldn't say that. While dynamically scoped Vars are meant to be context > that you implicitly pass down to your call stack, ThreadLocals are > references that you can pass around explicitly at will. > > Java ThreadLocals also provide an .initialValue() callback to override, > which is not provided by Vars. Vars can't even be (idiomatically) > initialized to a thread-bound value. > > I think that the fact that dynamically scoped Vars are implemented by > ThreadLocals is an implementation detail, and it is not a feature, it is > more of a limitation. (I guess implementing it otherwise is difficult, if > viable at all). > > Thanks > -- 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 Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.