Neeraj Kashyap
Neeraj Kashyap

Reputation: 130

clojure-koans: dosync inside do?

Was working my way through the clojure koans when I came across an interesting one in the refs section:

(= "better" (do
      (dosync (ref-set the-world "better"))
      @the-world))

I replaced this with:

(= "better" (dosync (ref-set the-world "better") @the-world))

to the same effect.

Is there any meaningful difference between the two? Why did the koan creator choose the first one?

Upvotes: 0

Views: 120

Answers (1)

cfrick
cfrick

Reputation: 37073

The difference is, that you deref (read) that value within or outside of the transaction. If the deref is part of the "transaction" (the dosync), then the value you get back it guaranteed to be the one you wrote as it's all part of one operation.

For this example the apparent effect is of course the same, since nothing works concurrently on your ref. But if you have something else banging on it it looks like this:

user=> (def the-world (ref nil))
#'user/the-world
user=> (def disruptor (future (loop [] (dosync (ref-set the-world 0)) (recur))))
#'user/disruptor
user=> @the-world
0
user=> (dosync (ref-set the-world 1) @the-world)
1
user=> (dosync (ref-set the-world 1) @the-world)
1
user=> (do (dosync (ref-set the-world 1)) @the-world)
0
user=> (do (dosync (ref-set the-world 1)) @the-world)
0

The disruptor set the value to 0 in a background thread repeatedly. So deref in/outside the transaction now matters.

Upvotes: 4

Related Questions