Reputation: 31
I'm new to Clojure and have been trying to understand its transaction model.
When playing with alter
and commute
, I noticed that if I alter
a ref after commute
it, then the transaction will not commit anything (or makes no change to anything).
For example:
(def counter (ref 0))
(def i (ref 0))
(future (dosync
(ref-set counter 1)
(ref-set i 1)
(commute counter inc)
(alter counter inc)))
Both @counter
and @i
will be 0, but if I swap commute
and alter
or use two commute
s or two alter
s in this case it will produce the desired result (3 and 1, respectively).
I've read some posts explaining that the behavior of commute
and alter
is a bit different in that commute
is actually executed twice in a transaction (one where it stands, the other at the "commit" stage) and ignores inconsistent snapshots of the ref. I'm just confused by the strange behavior of the combination of these two.
Could anyone help explain how it works? Thanks in advance!
Upvotes: 3
Views: 110
Reputation: 29958
The commute
function is useful only in very narrow (i.e. rare) circumstances, where it may reduce lock contention at the cost of additional re-tries of the update function. It also makes the mental model of the transaction much more complicated, as your example shows (I had never seen this particular problem before, for example).
IMHO it is almost always better to use alter
instead of commute
since alter
is simpler and more bulletproof. Indeed, I would usually consider the use of commute
to be a case of premature optimization.
Upvotes: 0