Search code examples
clojurereset

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?


Solution

  • 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