I had a look at the references: http://clojure.org/vars#Vars%20and%20the%20Global%20Environment, http://clojuredocs.org/clojure_core/clojure.core/binding
as well as clojure and ^:dynamic and Clojure Dynamic Binding
I still don't understand why there is a need for binding
at all as every program I have written have been without them and I can find ways to write the examples in the conventional way - which I find more understandable. Are there examples of projects/programming paradigms that make used of this?
for example... in the animal speak example, you can get a similar effect with:
(def dog {:name "Dog" :sound "Woof"})
(def cat {:name "Cat" :sound "Meow"})
(defn speak [animal]
(str (:name animal) " says " (:sound animal))
(println (speak dog))
(println (speak cat))
no macros, no dynamic binding... still very clean.
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.
In Clojure, variables are defined by the 'def' keyword. It's a bit different wherein the concept of variables has more to do with binding. In Clojure, a value is bound to a variable.
There isn't strictly a need for them: as you rightly observe you can do anything you like without binding
, and indeed if binding
didn't exist then you could re-implement it relatively easily using macros and Java's ThreadLocal
s.
Binding is however useful as a way of passing dynamic context to a function without needing to explicitly pass a parameter.
It is particularly useful when you are composing deeply nested higher order functions and don't want to add extra parameters to every single function in the call stack in order to pass some value to the lower level functions embedded deep within.
To build on your example:
(def ^:dynamic *loud-noises* false)
(defn speak [animal]
(str (:name animal) " says "
(let [sound (:sound animal)]
(if *loud-noises* (.toUpperCase sound) sound))))
(speak dog)
=> "Dog says Woof"
(binding [*loud-noises* true]
(speak dog))
=> "Dog says WOOF"
Note I didn't need to add an extra parameter to the speak
function to get different behaviour. Adding an extra parameter would be trivial in this case, but imagine if the speak
function was buried deep within a complex higher order function.....
Still, I think the best advice overall is to avoid dynamic binding unless you really need it. It is usually better to add explicit parameters if you can: direct parameters make it easier to test and reason about functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With