>
> which brings up the limitation of implementing dynamically scoped vars 
> with ThreadLocal: It would be reasonable to expect that the bindings of 
> dynamic vars propagate to all code inside the same function, even if 
> executed by a different thread
>

This is not a limitation, this was done on purpose. Traditional dynamic 
vars are not thread safe and don't play well inside threaded environments. 
Clojure purposely restricted the scope to single threads. You can propagate 
it explicitly by using (bound-fn). Dynamic vars in Clojure were designed as 
a concurrency primitive, not as an implicit parameter, though it is fine to 
use them for that if you know what you are doing. You can see that from 
Rich Hickey's Clojure slides: https://i.imgur.com/jx2vtPb.png

A Clojure var is not only an object, it is a language construct. And when 
> you make it dynamic, you can bind and re-bind it with different values as 
> your functions are invoked within each other. This is something a 
> ThreadLocal can't do, and it makes the dynamic var a different kind of 
> beast, used for different purposes. A dynamic var emulates a local var that 
> you don't need to pass as a parameter to functions down the stack.
>

You don't need to make them dynamic to re-bind them. The symbol is 
immutably bound to the Var, so to allow re-binding of def in Clojure, all 
symbols are mapped to Vars instead of the value being defed, which are 
mutable data structures with thread safety features. The first thread 
safety feature is volatile access across threads of a root pointer with 
automatic deref. Volatile is needed to guarantee that as soon as you 
re-def, all access will see the new def and not the old. The second thread 
safety feature is thread isolated value overrides. This is useful when you 
don't need threads to cooperate on the same data, but you need all of them 
to have their own copy to work with. Each feature is optional. So if you 
only want thread isolation, you create a dynamic with no root. If you only 
want volatile root, you create a non dynamic var. If you want both, you can 
do that too.

So yes, it is not exactly like ThreadLocal, but I guess this is the biggest 
thing I disagree about, it's that for every use case Var can be used for, 
there is nothing wrong with using it, even if a ThreadLocal could also be 
used. In fact, I'd frown upon someone using ThreadLocal when Var would work.

Dynamic vars are required to be global in Clojure, because Clojure will 
> check that your symbols have been defined, but they wouldn't need to.


Dynamic vars are not required to be global in Clojure, you can use 
(with-local-vars) if you only need them to be local. I know it is a bit 
complicated to refer to their instance directly, and there's no constructor 
for them, only indirect ones like def and (with-local-vars), but they can 
be used as a simple instance if you want. You can refer to the instance by 
using (var). You can pass this instance around. You can create local 
versions of them. You can even call into their java constructor if you want 
more control on them, at which point, you can fine tune when to push and 
pop on them. Now, I don't advise you use them through their Java interface, 
but you can if you want.

This is not unimportant, and indicates that vars and ThreadLocals are meant 
> for different purposes. A ThreadLocal will guarantee a new, different value 
> for each thread. For Vars, you need to manually do that at thread creation, 
> and it may be tricky for threads that you don't create, if possible.
>

This I agree with, and that's the only use case I can think of where 
ThreadLocal would be better. Slight correction though, ThreadLocals won't 
guarantee that, but can be made too, by overriding their init method. By 
default they return null otherwise. Vars and ThreadLocal are meant to be 
tools in my opinion, and they overlap quite a bit in functionality, and 
where it overlaps, I see no reason to use ThreadLocal over Vars, especially 
when considering that in most cases, you'll put your ThreadLocal inside a 
Var when using it from Clojure.

Regression: The reason that I brought up this discussion is that I didn't 
> understand why clojure.tools.logging uses a dynamic var for enforcing the 
> use of a specific *logger-factory*. Does anybody have an explanation for 
> that?
>

This lets you override the factory used to create the logger if you need 
too, within a particular thread and binding block. I'm not sure when that 
would come in handy for tools.logging, but I assume it sometimes is.

By the way, as I revisit your initial question:

Clojure encourages avoiding the use of vars as global thread-local storage, 
> by restricting their use to dynamic binding only.
>

I can see now what you were asking. The "dynamic" part is the idea that the 
value is pushed and poped within entry and exit of a binding block. I doubt 
Clojure has anything against global thread-local storage, but it wanted to 
provide a "dynamic" behavior that was also thread safe. I think this is 
what you meant by they are designed for different purpose. In that sense, 
yes, you're correct 100%. Clojure would have implemented it with other 
things if ThreadLocal did not exist. But, it would have implemented it to 
still behave as it does no matter what, so there's no accidental 
abstraction leak here from having used the ThreadLocal.

Having said that, if you look at the details, you might realize that in 
most cases, ThreadLocal should have been designed the way Vars have, and it 
would have been a better construct. In my opinion, in all cases except when 
you want default initialization. The reason I say that is because it is not 
possible to re-use a thread in Java. So effectively, a Thread == A single 
run through a call stack. In that case, it would be way better if the 
ThreadLocal value for that thread would be automatically removed for you 
when exiting. The fact it is not can cause issues in certain scenarios. Now 
if using Thread Pools, the Threads are actually special Threads which 
contain a loop within them, so the "Call Stack" is infinite. The Threads in 
the pool are then assigned to pick up execution when some are available. So 
the Thread is not really re-used, but is simply never done being used. Once 
again, if you use a ThreadLocal in java, because that Thread is never done, 
the value for the ThreadLocal remains on it infinitely. This also causes 
issues most of the time, either it creates leaks, because references are 
not garbage collected, or it causes the next execution to not get a fresh 
value. Because of these details, I think Clojure did it better by 
restricting it to be dynamic.

P.S.: Thanks for all the healthy back and forth, it forced me to really 
refresh and solidify my understanding of Clojure Vars.

On Tuesday, 28 March 2017 14:44:58 UTC-7, Ernesto Garcia wrote:
>
> Right, except each thread gets its own binding. So it's not necessarily 
>> that you'll get the value of the last binding up the call stack. This will 
>> only be true if you are in the same thread also.
>
>
> The last binding up in the call stack implies that you are in the same 
> thread, but I think I know what you mean, which brings up the limitation of 
> implementing dynamically scoped vars with ThreadLocal: It would be 
> reasonable to expect that the bindings of dynamic vars propagate to all 
> code inside the same function, even if executed by a different thread.
>  
>
>> ThreadLocal is an object, and so is a Clojure Var.
>>
>
> A Clojure var is not only an object, it is a language construct. And when 
> you make it dynamic, you can bind and re-bind it with different values as 
> your functions are invoked within each other. This is something a 
> ThreadLocal can't do, and it makes the dynamic var a different kind of 
> beast, used for different purposes. A dynamic var emulates a local var that 
> you don't need to pass as a parameter to functions down the stack.
>  
>
>> In both, you'll probably want to store the instance through a globally 
>> accessible name, like with def in Clojure or a static in Java. You don't 
>> have too, but I don't see the use case for a local reference to the 
>> ThreadLocal or the Var.
>>
>
> Dynamic vars are required to be global in Clojure, because Clojure will 
> check that your symbols have been defined, but they wouldn't need to.
>
> ThreadLocals don't need to be global either, you can define them in the 
> smaller scope where they are used.
>  
>
>> Then there's the details, like Vars have a default global scope value, 
>> while ThreadLocal has a default init method if you get before a set.
>>
>
> This is not unimportant, and indicates that vars and ThreadLocals are 
> meant for different purposes. A ThreadLocal will guarantee a new, different 
> value for each thread. For Vars, you need to manually do that at thread 
> creation, and it may be tricky for threads that you don't create, if 
> possible.
>
>
> Regression: The reason that I brought up this discussion is that I didn't 
> understand why clojure.tools.logging uses a dynamic var for enforcing the 
> use of a specific *logger-factory*. Does anybody have an explanation for 
> that?
>
> Thanks,
> Ernesto
>
>>

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

Reply via email to