If I understand Clojure's dynamic vars correctly, in a context where some
var *bar* is already thread-bound, the following code:

 (binding [*bar* new-val]
   (foo))

is semantically equivalent to:

 (let [old-val *bar*]
   (set! *bar* new-val)
   (try
     (foo)
     (finally
       (set! *bar* old-val))))

The latter version appears to be 3 to 4 times faster if (foo) does nothing.

The binding macro in the first version expands to something like:

 (push-thread-bindings (hash-map (var *bar*) new-val))
 (try
   (foo)
   (finally (pop-thread-bindings)))

So the binding macro uses some stack implementation instead of just
remembering the old value on the JVM call stack like the faster version
does. I am probably missing something, but why do dynamic vars need to
have their own stack for bindings?

Also I noticed that replacing "(hash-map (var *bar*) new-val)" with
"{(var *bar*) new-val}" in the above macro expansion makes it about 1.5-2
times faster. This could also be fixed in the source of the binding
defmacro by changing the following line:

 (push-thread-bindings (hash-map ~@(var-ize bindings)))

to:

 (push-thread-bindings ~(apply hash-map (var-ize bindings)))

--
Mikhail

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

Reply via email to