What happens when you create nested dosync calls? Will sub-transactions be completed in the parent scope? Are these sub-transactions reversible if the parent transaction fails?
1 Answers
If you mean syntactic nesting, then the answer is it depends on whether the inner dosync
will run on the same thread as the outer one.
In Clojure, whenever a dosync
block is entered, a new transaction is started if one hasn't been running already on this thread. This means that while execution stays on a single thread, inner transactions can be said to be subsumed by outer transactions; however if a dosync
occupies a position syntactically nested within another dosync
, but happens to be launched on a new thread, it will have a new transaction to itself.
An example which (hopefully) illustrates what happens:
user> (def r (ref 0))
#'user/r
user> (dosync (future (dosync (Thread/sleep 50) (println :foo) (alter r inc)))
(println :bar)
(alter r inc))
:bar
:foo
:foo
1
user> @r
2
The "inner" transaction retries after printing :foo
; the "outer" transaction never needs to restart. (Note that after this happens, r
's history chain is grown, so if the "large" dosync
form were evaluated for a second time, the inner dosync
would not retry. It still wouldn't be merged into the outer one, of course.)
Incidentally, Mark Volkmann has written a fantastic article on Clojure's Software Transactional Memory; it's highly recommended reading for anyone interested in gaining solid insight into details of this sort.

- 83,634
- 13
- 201
- 212
-
Why the "syntactically" qualifier? And what does syntactically mean? I am a common lisper and I am accustomed to "lexically", as in closing over variables that are lexically visible: (let ((x 42)) (lambda () x)) vs dynamically (ie, bound in the call stack somewhere). – kennytilton Apr 03 '16 at 21:36