kkaatii
kkaatii

Reputation: 31

Clojure: commute before alter within one transaction causes the transaction to fail

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 commutes or two alters 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

Answers (1)

Alan Thompson
Alan Thompson

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

Related Questions