Search code examples
clojurefuturedynamic-variables

Why does dynamic binding affect the body of future?


I'm trying to reproduce pitfalls of dynamic vars described by Chas - http://cemerick.com/2009/11/03/be-mindful-of-clojures-binding/.

Consider the following snippet:

(def ^:dynamic *dynamic-x* 10)

(defn adder [arg]
  (+ *dynamic-x* arg))

(adder 5) ;; returns 15

(binding [*dynamic-x* 20]
  (adder 5)) ;; returns 25

(binding [*dynamic-x* 20]
  @(future (adder 5))) ;; returns 25 (!)

Actually, I was expecting that 3rd case will return 15, as soon as adding is performed on the separate thread and current thread local value of *dynamic-x* (which I supposed to be 10) should be used. But, unexpectedly for me, it returns 25.

Where am I wrong?


Solution

  • It is the design of future that the dynamic bindings are passed to the other threads in which the future body will be executed (Look into the source of future, which defers to future-call, which uses a function called binding-conveyor-fn which explicitly copies the thread-local bindings).

    The motivation for this IMO is that when using future you want to run your computation in the same "logical thread", only you're actually doing it in another Java Thread for performance reasons.

    I agree it would deserve to be explicitly documented :)