1.3.0 permalink Arrow_down_16x16

binding

clojure.core

  • (binding bindings & body)
binding => var-symbol init-expr

Creates new bindings for the (already-existing) vars, with the
supplied initial values, executes the exprs in an implicit do, then
re-establishes the bindings that existed before. The new bindings
are made in parallel (unlike let); all init-exprs are evaluated
before the vars are bound to their new values.

3 Examples top

  • ;; Here are the definitions.
    (defn mymax [x y]
      (min x y))
    
    (defn find-max [x y]
      (max x y))
    
    user=> (let [max mymax]
             (find-max 10 20))
    
    20 ;let is ineffective outside current lexical scope
    
    
    user=> (binding [max mymax]
             (find-max 10 20))
    
    10 ;because max is now acting as min
  • ;; As of Clojure 1.3, vars need to be explicitly marked as ^:dynamic in order for
    ;; them to be dynamically rebindable:
    
    user=> (def ^:dynamic x 1)
    user=> (def ^:dynamic y 1)
    user=> (+ x y)
    2
    
    ;; Within the scope of the binding, x = 2 and y = 3
    
    user=> (binding [x 2 y 3]
             (+ x y))
    5
    
    ;; But once you leave the binding's scope, x and y maintain their original
    ;; bindings:
    
    user=> (+ x y)
    2
  • ;;Use t like a "template"
    
    (declare ^:dynamic t)
    
    (defn addt [] 
      (+ t 10))
    
    (binding [t 1]
      (addt))
    => 11
Log in to add / edit an example.

See Also top

Log in to add a see also.

Plus_12x12 Minus_12x12 Source clojure/core.clj:1734 top

(defmacro binding
  "binding => var-symbol init-expr

  Creates new bindings for the (already-existing) vars, with the
  supplied initial values, executes the exprs in an implicit do, then
  re-establishes the bindings that existed before.  The new bindings
  are made in parallel (unlike let); all init-exprs are evaluated
  before the vars are bound to their new values."
  {:added "1.0"}
  [bindings & body]
  (assert-args binding
    (vector? bindings) "a vector for its binding"
    (even? (count bindings)) "an even number of forms in binding vector")
  (let [var-ize (fn [var-vals]
                  (loop [ret [] vvs (seq var-vals)]
                    (if vvs
                      (recur  (conj (conj ret `(var ~(first vvs))) (second vvs))
                             (next (next vvs)))
                      (seq ret))))]
    `(let []
       (push-thread-bindings (hash-map ~@(var-ize bindings)))
       (try
         ~@body
         (finally
           (pop-thread-bindings))))))
Vars in clojure.core/binding:
Used in 0 other vars

Comments top

1 comment(s) for binding.

The first example (binding mymax to max) appears to be broken. The last line generates the error:

  IllegalStateException Can't dynamically bind non-dynamic var: clojure.core/max

I tried inserting (.setDynamic #'max) at the top, and it got rid of the error, but the binding didn't seem to actually happen. I.e. the last line prints 20.


The only way I could get it to work is by redefining max from scratch as dynamic:
(defn ^:dynamic max
  ([x] x)
  ([x y] (. clojure.lang.Numbers (max x y)))
  ([x y & more]
   (reduce max (max x y) more)))

After THIS the first example succeeds.


The moral of the story - I guess you can't easily bind built-in functions. You need to write your functions with the intention of them being bindable. And I guess the first example should simply be removed?
Log in to add a comment.