Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #9 from stuntgoat/master

Changed "Bindings" to "Vars"
  • Loading branch information...
commit f909d7fdfb676765349966c9a6a4c3ea540d1b58 2 parents ff03cdd + 2ca47fc
@mvolkmann authored
Showing with 123 additions and 79 deletions.
  1. +123 −79 article.html
View
202 article.html
@@ -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,54 @@
(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. It provides a
+ mechanism to define metadata, <code>:dynamic</code>, which allows a thread-local value
+ within the scope of a <code>binding</code> call.
+ 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 refers to the value of the root binding,
+ if accessed from another thread.
+ <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 +1230,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.