I'm learning clojure ref types and was trying to make a robust counter generating function. Is there any error or improvement on the code? is there a simpler way? (I want the function to be thread-safe)
(defn get-counter []
(let [a (agent 0)]
(fn []
(let [p (promise)]
(send a (fn [old]
(deliver p old)
(inc old)))
@p))))
In some situations it works better with a future but I'm not sure why it is.
(defn get-counter []
(let [a (agent 0)]
(fn []
(let [p (promise)]
@(future
(send a (fn [old]
(deliver p old)
(inc old)))
@p)))))
EDIT - What I wanted the counter for. I was testing how the transactions worked and wanted a way of seeing the transaction retries. I wanted a function that returns numbers in sequence and never repeats a number or skips one.
(def counter (get-counter))
(def r (ref []))
(def a (atom []))
(repeatedly 2 #(future (dosync (let [c (counter)]
(future (dosync (Thread/sleep 50)
(let [c2 (counter)]
(swap! a conj [:foo c c2])
(alter r conj [:foo c c2]))))
(swap! a conj [:bar c])
(alter r conj [:bar c])))))
(deref r)
=> [[:bar 0] [:bar 2] [:foo 1 6] [:foo 0 9] [:foo 2 11]]
(deref a)
=> [[:bar 0] [:bar 1] [:bar 2] [:foo 1 3] [:foo 0 4] [:foo 2 5] [:foo 1 6] [:foo 0 7] [:foo 2 8] [:foo 0 9] [:foo 2 10] [:foo 2 11]]
From Elogent's answer I'm guessing I could just do something like:
(defn get-counter []
(let [a (atom 0)]
(fn []
(swap! a inc))))
2nd EDIT - The only problem I could see in this solution is that if two calls happen very close to each other, the first call might get the greater value if it needs to retry.
Since another thread may have changed the value in the intervening time, it may have to retry, and does so in a spin loop. http://clojure.org/reference/atoms