2

What's the difference between?

1.

(def x (ref 0))
(dosync
  (commute x f))

2.

(def x (atom 0))
(swap! x f))

These two examples work equally

n2o
  • 6,175
  • 3
  • 28
  • 46
Nawa
  • 2,058
  • 8
  • 26
  • 48
  • 2
    The premise of this question is false,`commute` will throw an exception when called on an atom. Perhaps you wanted to know the difference between `alter` and `commute`? If so that is answered here:http://stackoverflow.com/questions/4999281/ref-set-vs-commute-vs-alter – noisesmith Mar 27 '14 at 00:32
  • 2
    If you are wondering about the differences between vars, refs, atoms, and agents, I recommend [this post](http://stackoverflow.com/a/9136699/2472391). If you are wondering about the ways to change a ref, I recommend [this post](http://stackoverflow.com/a/4999888/2472391). If you are wondering about atoms, I recommend [this link](http://clojure.org/atoms), and then rephrasing your question. – galdre Mar 27 '14 at 02:21
  • @noisesmith sorry, ref in first example – Nawa Mar 27 '14 at 07:07
  • Hope this topic is helpful: http://stackoverflow.com/questions/9132346/clojure-differences-between-ref-var-agent-atom-with-examples/9136699#9136699 – xtang Mar 28 '14 at 07:39

1 Answers1

8

If you have only one ref and one atom, there actually is no big difference. I think you might learn something about the difference of atoms and refs.

commute is a function which can be called in any place in the dosync block. Clojure itself chooses when to execute an commute inside this block.

Maybe I explan it with a small example:

(def x (ref 0))
(def y (ref 0))
(dosync (alter x inc)
        (alter y dec))

alter changes the value of a ref inside a dosync block. Because refs are coordinated and synchronous, we need to place them inside this block. If here occurs an error while altering one of the refs, the whole block fails and your refs have the same value as they had before calling the alters.

The difference to commute is the following: If we have the following code block

(def x (ref 0))
(def y (ref 0))
(dosync (commute x inc)
        (alter y dec))

If an error occurs here while changing the value of your refs, commute is still called and it changes your ref. It does not care about the result of the alter and even if the alter fails, commute does increment x. Clojure can choose when to call commute, so it can be executed even if an error occurs.

The big difference to atoms is that atoms are not coordinated. If there are multiple swap! on one atom, maybe just the first swap! will be executed. One of my projects got stuck on this issue, I had to ensure that the first swap! has terminated before the next swap! is called.

So again: Think of what you really need. Do you need an atom or some refs? If you choose refs, you have the choice between alter, which is executed at the position you want it to, or commute where Clojure can decide when to call it (the call is then commutative).

If you choose an atom, you can only change one value while this atom is executed. If another call trys to swap! the value, it is rejected.

n2o
  • 6,175
  • 3
  • 28
  • 46