Idiomatic use case for set! in Clojure - clojure

What are the idiomatic use-cases for set! in Clojure?
It's not easy to find uses! I grepped in some of the more popular Clojure OSS projects and there's almost none. The only uses I could find are for setting globals like warn-on-reflection, though it's unclear why these are not just set locally with binding.
Any suggestions?

set! can be used, in combination with thread-local binding, to allow functions to communicate across the call stack. It is often a convenient way to share state across mutually-recursive functions.
The Clojure compiler is a good example — even though it is implemented in Java — of using of dynamic Vars to keep track of internal state.

You have answered your own question. When you type:
(def foo 42)
(def ^:dynamic bar 43)
you are creating a global variable. In most programming languages, we try to minimize the use global variables as they introduce more complexity and more difficulty in understanding the code (this leads to more errors!). When we do need global variables, we try to minimize the mutation of those global variables. This is why you rarely see set!, var-set, var-get, and alter-var-root used in Clojure code.
When Clojure code does need to mutate global state, binding is often preferred as the var in question returns to its previous state when the current thread leaves the scope of the binding form. Another benefit is that other threads remain unaffected by any binding mutations made by the current thread.
There are several ways to manipulate global variables in Clojure. The answer changes a bit for a normal var compared to a dynamic var. Here are some examples:
(ns tst.clj.core
(:use clj.core
tupelo.test)
(:require
[tupelo.core :as t] ))
(t/refer-tupelo)
(def fred 0)
(def ^:dynamic *barney* 0) ; normally use "earmuffs" for dynamic vars
(def ^:dynamic wilma 0) ; you aren't forced to use use them (but you should!)
(def betty 29)
(dotest
(throws?
(binding [fred 1] ; can't bind non-dynamic var
(is= fred 1)
(throws? (set! fred 2))
(is= fred 2)))
(is= fred 0)
(throws? (set! fred 2)) ; can't set it
(is= fred 0)
(throws? (var-set #'fred 3)) ; java.lang.IllegalStateException: Can't change/establish root binding of: fred with set
(is= fred 0)
(is= (var-get #'fred) 0)
(binding [*barney* 3]
(is= *barney* 3)
(set! *barney* 4) ; works fine
(is= *barney* 4))
(is= *barney* 3) ; original value once leave binding scope
(binding [wilma 6]
(is= wilma 6)
(set! wilma 7) ; this works
(is= wilma 7)
(alter-var-root #'wilma inc) ; this doesn't work!
(is= wilma 7))
(is= wilma 1) ; the `inc` altered the root value, not the dynamic value in the `binding`
(alter-var-root #'wilma #(+ 23 %)) ; can alter root value outside of binding
(is= wilma 24)
(is= betty 29)
(alter-var-root #'betty inc) ; non-dynamic vars can have root value altered
(is= betty 30)
)

Related

What is the difference between using reset! and a new def to change the value of a variable associated to an atom in Clojure?

According to Clojure's documentation, reset! can be used as:
Sets the value of atom to newval without regard for the current value.
Returns newval.
Thus, I can do:
user> (def my-test (atom 666))
#'user/my-test
user> my-test
#<Atom#66d7a880: 666>
user> #my-test
666
user> (reset! my-test 77)
77
user> my-test
#<Atom#66d7a880: 77>
user> #my-test
77
But, is there any difference between using another def instead of reset!?
user> (def my-test (atom 666))
#'user/my-test
user> my-test
#<Atom#66d7a880: 666>
user> #my-test
666
user> (reset! my-test 77)
77
user> my-test
#<Atom#66d7a880: 77>
user> #my-test
77
;;;; converting it back to the original value via def
user> (def my-test (atom 666))
#'user/my-test
user> #my-test
666
user> my-test
#<Atom#7ce4f432: 666>
user>
Just by reading the experiments on the REPL I cannot identify any difference. But I am new to Clojure, so I am probably naive here.
If there is any difference, why should I use reset! instead of a new def?
You can see the answer in the REPL output in your question. When you write (reset! a 1), you give a new value to the existing atom. When you write (def a (atom 1)), you get a brand new atom. Why does this matter? Because someone may have another reference to the old atom: in the former case they see the new value, and in the latter case they don't. Compare, for example:
(def a (atom 0))
(defn counter [c] (fn [] (swap! c inc)))
(def count-up (counter a))
(count-up) ; 1
(count-up) ; 2
(reset! a 0)
(count-up) ; 1 again
with
(def a (atom 0))
(defn counter [c] (fn [] (swap! c inc)))
(def count-up (counter a))
(count-up) ; 1
(count-up) ; 2
(def a (atom 0))
(count-up) ; 3, because the old atom still holds 2
Changes to atoms are always free of race conditions. New-def-ing is not.
A Clojure Var is meant to be a global value that, in general, never changes (as always, there are exceptions to every rule). As an example, function declarations are normally stored in a Var.
A Clojure Atom is meant to point to a value that can change. An atom may be held in a global Var or a local variable binding (e.g. in a (let ...) form). Atoms are thread-safe (this is one of their primary purposes).
If you are just playing around with experimental code with only one thread, you can do a lot of sloppy or dangerous stuff and there is no problem. However, you should learn how to use each tool for its intended purpose.
More detailed discussion:
Brave Clojure
Book Getting Clojure
Clojure.org - Vars
Clojure.org - Atoms
clojuredocs.org - atom
Clojure CheatSheet
def creates a new atom (means allocate new memory space for an atom - setting it up - setting a pointer), while reset! just resets an existing atom (just changing value in the cell the pointer points to).
Therefore it is logical that reset! must be much cheaper (faster execution and less usage of resources) than def which you can test by:
(def n 10000000)
(time (dotimes [_ n] (def a (atom 1))))
## "Elapsed time: 2294.676443 msecs"
(def b (atom 1))
(time (dotimes [_ n] (reset! b 1)))
## "Elapsed time: 106.03302 msecs"
So reset! is one magnitude of order faster than def.

repeatedly vs. binding

(def ^:dynamic *d* 1)
(binding [*d* 2]
(println *d*)
(repeatedly 1 #(println *d*)))
Output:
2
1
Why? Why does the function inside the repeatedly see the value of the dynamic var from outside the binding?
By the way, I checked (.getId (java.lang.Thread/currentThread)) inside and outside the anonymous function: it's the same.
The lazy sequence created by repeatedly is returned from the form, and then realized only when printed via the REPL, after the binding has been "unwound," and it is at this point that the anonymous function is being called. To see that this is the case, try these two variations:
(binding [*d* 2]
(println *d*)
(let [x (repeatedly 1 #(println *d*))]
(println (realized? x))
x))
and
(binding [*d* 2]
(println *d*)
(doall (repeatedly 1 #(println *d*))))
The second variation forces the sequence to be fully realized while still within the scope of the binding.
Note that another way to force the issue is to "capture" the binding by using bound-fn:
(binding [*d* 2]
(println *d*)
(repeatedly 1 (bound-fn [] (println *d*))))

What is the difference between def and defonce in Clojure?

What is the difference between def and defonce in Clojure?
When to use def over defonce or vice versa?
defonce is skipped when variable is already defined.
user> (def a 1) ;;=> #'user/a
user> a ;;=> 1
user> (def a 2) ;;=> #'user/a
user> a ;;=> 2
user> (defonce b 1) ;;=> #'user/b
user> b ;;=> 1
user> (defonce b 2) ;;=> nil
user> b ;;=> 1
Defonce only binds the name to the root value if the name has no root value.
For example, like Jay Fields blogs about, it can be used in conjunction when you want to reload namespaces but you might not need to reload all.
(defonce ignored-namespaces (atom #{}))
(defn reload-all []
(doseq [n (remove (comp #ignored-namespaces ns-name) (all-ns))]
(require (ns-name n) :reload )))
As for when to use defonce, if you're using system with hot reloading (CLJS with mount and re-frame for example), defonce is useful to keep the state between reloads.
Similar situation when you re-evaluate source file yourself (e.g. in REPL) but want to keep the value of the var bound to the symbol.

For loop not working inside midje test?

Found some odd behavior in midje, not sure if it's midje related, or due to my misunderstanding of some clojure constructs, but it's puzzling:
Inside a facts statement, a for loop is not getting called:
(ns t1
(:require [midje.sweet :refer :all ] )
)
(facts
(println "ok") ; -- this prints fine
(for [val '(1 2 3)] (println val)) ; this does not
(fact "junk"
(> (.length "aaaaha") 3) => true ))
Thought maybe it had something to do with the for being overwritten in the ns but calling clojure.core/for behaves similarly.
clojure.core/for "...yields a lazy sequence..."
You need to realize the sequence to see its side effects.
(doall (for [val '(1 2 3)] (println val)))
I'd suggest using something more appropriate like clojure.core/doseq:
(doseq [val '(1 2 3)] (println val))

Clojure: binding vs. with-redefs

clojure.core has the macros bindings and with-redefs. Looking at the docstrings and the examples on clojuredocs.org, they seem to do something very similar. What is the difference and which one should I use in which situations?
Clojure Vars can have thread-local bindings. binding uses these, while with-redefs actually alters the root binding (which is someting like the default value) of the var.
Another difference is that binding only works for :dynamic vars while with-redefs works for all vars.
Examples:
user=> (def ^:dynamic *a* 1)
#'user/*a*
user=> (binding [*a* 2] *a*)
2
user=> (with-redefs [*a* 2] *a*)
2
user=> (binding [*a* 2] (doto (Thread. (fn [] (println "*a* is " *a*))) (.start) (.join)))
*a* is 1
#<Thread Thread[Thread-2,5,]>
user=> (with-redefs [*a* 2] (doto (Thread. (fn [] (println "*a* is " *a*))) (.start) (.join)))
*a* is 2
#<Thread Thread[Thread-3,5,]>
You can use the (undocumented) binding-conveyor-fn to convey thread-local bindings into new threads:
user=> (binding [*a* 2] (doto (Thread. (#'clojure.core/binding-conveyor-fn (fn [] (println "*a* is " *a*)))) (.start) (.join)))
*a* is 2
#<Thread Thread[Thread-5,5,]>