Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Edited "Bindings" section for clarity and readability.

Changed "Bindings" to "Vars" since Var is the name used in the official Clojure documentation.
- moved comments in code examples to the line above the code being documented. This was done for readability.
- edited example code for readability.
- edited text to clarify the overall idea of mutable values within the context of execution threads.
  • Loading branch information...
commit a246ea82deed55d79ce4cd10bfa777717e408f9a 1 parent c45704e
music authored
Showing with 121 additions and 79 deletions.
  1. +121 −79 article.html
200 article.html
View
@@ -185,7 +185,7 @@
</tr>
<tr>
<td colspan="1" rowspan="1" style="padding:5px">
-<a href="#Bindings">Bindings</a>
+<a href="#Vars">Vars</a>
</td>
<td colspan="1" rowspan="1" style="padding:5px">
<a href="#Destructuring">Destructuring</a>
@@ -1162,66 +1162,52 @@
(including UNIX, Linux and Mac OS X), type ctrl-d.
</p>
- <h2><a name="Bindings">Bindings</a></h2>
+ <h2><a name="Vars">Vars</a></h2>
<p>
- Clojure doesn't support variables.
- Instead it provides bindings which are like variables
- that are not intended to be changed after a value is assigned.
- There are global bindings, thread-local bindings,
- bindings that are local to a function,
- and bindings that are local to a given form.
+ Clojure provides bindings to Vars, which are containers bound to mutable
+ storage locations. There are global bindings, thread-local bindings,
+ bindings that are local to a function, and bindings that are local to a given form.
</p>
- <p>
- The <code>def</code> special form creates a global binding
- and optionally gives it a "root value" that is
- visible in all threads unless a thread-local value is assigned.
- <code>def</code> can also be used to change the root value
- of an existing binding.
- However, doing this is frowned upon because it
- sacrifices the benefits of working with immutable data.
</p>
- <p>
- Function parameters are bindings that are local to the function.
+ Function parameters are bound to Vars that are local to the function.
</p>
<p>
- The <code>let</code> special form creates bindings
- that are local to that form.
+ The <code>def</code> macro binds a value to a symbol and provides
+ mechanism to assign that binding a thread-local value, via the <code>:dynamic</code> declaration.
+ In other words it allows re-definition of assigned value per execution thread
+ and scope. If the Var is not re-assigned to a new value in a separate
+ execution thread, the Var simply behaves like a global binding to that value.
+ <p>
+ The <code>let</code> macro creates bindings to Vars
+ that are bound to the scope within the statement.
Its first argument is a vector containing name/expression pairs.
- The expressions are evaluated in order and
- their results are assigned to the names on their left.
- These bindings can be used in the expressions
- that follow them in the vector.
- They can also be assigned to more than once to change their value.
- The remaining arguments to <code>let</code> comprise the body
- which is a set of expressions to be evaluated
- with the new bindings in scope.
- Functions that are called in the body cannot see
- the local bindings created by <code>let</code>.
- </p>
+ The expressions are evaluated in order and their results
+ are assigned to the names on their left.
+ These Vars can be used in the binding of other Vars declared within the vector.
+ The expressions following the Var declaration vector
+ contain the Var(s) that are executed only within the <code>let</code> scope.
+ Vars within functions that are called within <code>let</code> but
+ defined outside of that scope are not affected
+ by the declarations in the <code>let</code>'s vector.
+ </p>
<p>
<a name="binding">The</a> <code>binding</code> macro
is similar to <code>let</code>,
- but it temporarily gives new, thread-local values
- to existing global bindings.
- The new values are seen inside that form and also
- in functions called from inside it.
- When the <code>binding</code> form exits,
- the bindings revert to their previous values.
- </p>
- <p>
- Starting in Clojure 1.3, binding can only do this for dynamic vars.
- The example below demonstrates how to declare that a var is dynamic.
- </p>
- <p>
- Another difference is that <code>let</code>
- assigns values sequentially,
- allowing values to be based on previously set bindings,
- whereas <code>binding</code> assigns values in parallel.
- </p>
- <p>
- Symbols that are intended to be bound to new, thread-local values
+ but it gives new, thread-local values
+ to existing global bindings throughout the scopes
+ thread of execution.
+ The values of Vars bound within the <code>let</code>
+ vector argument are also used in functions, if they use
+ the same Var names, called from inside that scope.
+ When the execution thread leaves the <code>binding</code> macro's scope,
+ the global Var bindings revert to their previous values.
+ Starting in Clojure 1.3, binding can only do this for vars
+ declared <code>:dynamic</code>.
+ </p>
+ <p>
+ Vars intended to be bound to new, thread-local values
using <code>binding</code> have their own naming convention.
- These special symbols have names that
+ These symbols have names that
begin and end with an asterisk.
Examples that appear in this article include
<code>*command-line-args*</code>,
@@ -1242,54 +1228,110 @@
</p>
<p>
The following code demonstrates usage of
- <code>def</code>, <code>let</code> and <code>binding</code>.
+ <code>def</code>, <code>defn</code>, <code>let</code>, <code>binding</code>, and <code>println</code>.
</p>
<div class="code">
<pre xml:space="preserve">
-(def ^:dynamic v 1) ; v is a global binding
+
+ ; v is a global binding
+(def ^:dynamic v 1)
(defn f1 []
- (println "f1: v =" v)) ; global binding
+ (println "f1: v:" v))
(defn f2 []
- (println "f2: before let v =" v) ; global binding
- (let [v 2] ; creates local binding v that shadows global one
- (println "f2: in let, v =" v) ; local binding
+ (println "f2: before let v:" v)
+ ; creates local binding v that shadows global one
+ (let [v 2]
+ ; local binding only within this let statement
+ (println "f2: in let, v:" v)
(f1))
- (println "f2: after let v =" v)) ; global binding
+ ; outside of this let, v refers to global binding
+ (println "f2: after let v:" v))
(defn f3 []
- (println "f3: before binding v =" v) ; global binding
- (binding [v 3] ; same global binding with new, temporary value
- (println "f3: in binding, v =" v) ; global binding
- (f1))
- (println "f3: after binding v =" v)) ; global binding
+ (println "f3: before binding v:" v)
+ ; same global binding with new, temporary value
+ (binding [v 3]
+ ; global binding, new value
+ (println "f3: within binding function v: " v)
+ ; calling f1 with new value to v
+ (f1))
+ ; outside of binding v refers to first global value
+ (println "f3: after binding v:" v))
(defn f4 []
- (def v 4)) ; changes the value of the global binding
+ ; changes the value of v in the global scope
+ (def v 4))
+(println "(= v 1) => " (= v 1))
+(println "Calling f2: ")
(f2)
+(println)
+(println "Calling f3: ")
(f3)
+(println)
+(println "Calling f4: ")
(f4)
(println "after calling f4, v =" v)
+
</pre>
</div>
<p>
- The output produced by the code above follows:
- </p>
- <div class="code">
-<pre xml:space="preserve">
-f2: before let v = 1
-f2: in let, v = 2
-f1: v = 1 (let DID NOT change value of global binding)
-f2: after let v = 1
-f3: before binding v = 1
-f3: in binding, v = 3
-f1: v = 3 (binding DID change value of global binding)
-f3: after binding v = 1 (value of global binding reverted back)
-after calling f4, v = 4
-</pre>
-</div>
+ If you saved the shell script, described earlier, to execute
+ Clojure files from your terminal you can run the
+ preceding code by saving it to a file called
+ 'vars.clj' and excecuting it at the commandline like so:</p>
+<p>
+ <div class="code"><br>
+$ clj vars.clj&nbsp;&nbsp;
+<br>&nbsp;
+</div>
+ </p>
+The output produced by the code above follows:
+ <div class="code">
+<pre xml:space="preserve">
+; (= v 1) => true
+Calling f2
+f2: before let v: 1
+f2: in let, v: 2
+f1: v: 1
+f2: after let v: 1
+
+Calling f3
+f3: before binding v: 1
+f3: within binding function v: 3
+f1: v: 3
+f3: after binding v: 1
+
+Calling f4
+after calling f4, v: 4
+
+</pre>
+</div>
+ <p>
+<h4>Recap:</h4>
+</p>
+<p>
+ Notice in the first call to f2, the <code>let</code>
+ function's binding to v did not change value of the
+ first declared value to v, as is shown in the call to
+ f1 within the <code>let</code> statement- the value
+ of v in f1 is 1, not 2.
+</p>
+<p>
+ Next, inside f3 within the scope of the <code>binding</code> call,
+ the value of v was re-assigned within f1 since f1 was called within the
+execution thread of <code>binding</code> call's scope. Once the f3's function
+ execution thread exits from the <code>binding</code> call, v is
+ bound to the initially declared binding, 1.
+</p>
+<p>
+ When f4 is called, the binding of v is not within the context
+ of a new execution thread so v is bound to this new value, 4, in the global scope.
+ Remember that changing a global value is not necessarily a best
+ practice- it is presented in f4's definition for demonstration purposes.
+</p>
<h2><a name="Collections">Collections</a></h2>
<p>
Please sign in to comment.
Something went wrong with that request. Please try again.