Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by
{{thread-bound?}} returns true for thread-local bindings that were not bound by the current thread. This is at odds with the docstring, which states that if true is returned, {{set!}} should succeed.

ere is an example REPL session where a thread establishes a binding, those bindings are conveyed to a second thread, the second thread checks thread-bound? to see if it can set the binding, thread-bound? returns true indicating that the binding can be set, the second thread tries to set the binding, and the second thread gets an IllegalStateException:

    Clojure 1.5.1
    user=> (def ^:dynamic *set-me* nil)
    user=> (defn try-to-set [] (binding [*set-me* 1] (doall (pcalls #(if (thread-bound? #'*set-me*) (set! *set-me* (inc *set-me*)))))))
    user=> (try-to-set)
    IllegalStateException Can't set!: *set-me* from non-binding thread  clojure.lang.Var.set (Var.java:230)

*Approach:* thread-bound? should return false in the case where there is a binding *and* that binding was not established by the current thread. The patch adds a new function to Var as core does not have visibility into the non-public Var$TBox.

*Patch:* thread-bound.diff

*Screened by:* Alex Miller

4 Answers

0 votes

Comment made by: pjstadig

I have attached a patch that changes clojure.lang.Var and clojure.core/thread-bound? to only return true if a Var is set!-able.

0 votes

Comment made by: alexmiller

REPL example?

0 votes

Comment made by: joegallo

Sure thing, Alex -- here's a repl example I just ran this morning.

`; nREPL 0.1.7
user> (def ^:dynamic set-me nil)


user> (defn try-to-set [] (binding [*set-me* 1] (doall (pcalls #(if (thread-bound? #'set-me) (set! set-me (inc set-me)))))))


user> (try-to-set)
IllegalStateException Can't set!: set-me from non-binding thread clojure.lang.Var.set (Var.java:230)

0 votes
Reference: https://clojure.atlassian.net/browse/CLJ-1077 (reported by pjstadig)