Hi,
I've come across some strange behavior while playing around with refs at the REPL.
So I have a ref with a simple watcher function:
(defn watcher [_ r o n]
(printf "ref: %s old: %s new: %s time: %d\n" @r o n (System/currentTimeMillis))
(flush))
(def x (ref 2))
(add-watch x nil watcher)
I then evaluate the following expression two times in a row:
(future (dosync (ensure x) (Thread/sleep 3000) (alter x * 2)))
What I would expect to happen is that the watcher function should print the ref's value two times in a row, about 3 seconds apart.
But nothing happens.
When I then try to access the ref with another command such as
(dosync (ensure x) (alter x inc))
The REPL blocks completely. Once I did get the expected results several minutes later, another time I got this error message:
Execution error at reftest.core/eval24449 (form-init12758928819079876959.clj:34).
Transaction failed after reaching retry limit
What I find perplexing is that everything seems to work just fine when I evaluate this let-block:
(let [x (ref 2)]
(add-watch x nil watcher)
(println "start:" (deref x))
(future (dosync (ensure x) (Thread/sleep 3000) (alter x * 2)))
(future (dosync (ensure x) (Thread/sleep 3000) (alter x * 2)))
(dosync (ensure x) (alter x inc))
(println "end:" @x))
Is the behavior at the REPL some kind of bug or am I doing something wrong?
How can I make sure that such STM transactions don't fail in real code?