alex314159
alex314159

Reputation: 3247

Clojure promise inside atom map

I am trying to track requests to a server, and do something when the data is ready. I have the following code which seems to work but I wonder if there's a better way to do it - in particular I find it strange that, in the future below, I'm dereferencing a promise inside dereferencing an atom, with the atom possibly changing state.

(def requests (atom {:a (promise) :b (promise)}))
(future @(:b @requests) (println "b is ready"))
(swap! requests assoc :c (promise))
(deliver (:b @requests) 100)
>> b is ready

Thank you,

Upvotes: 2

Views: 204

Answers (2)

amalloy
amalloy

Reputation: 92117

The main issue I see with this approach is that you put this promise inside an atom, but if anyone ever actually mutates the atom to contain a different promise, your program will break: the watcher will be waiting on a promise that nobody else has a reference to. Instead, I'd put the promise inside some immutable structure shared by the two parts of the code that need to communicate.

You could be a bit fancier and use a core.async channel instead of a promise, but if you only ever need to deliver a single value, a promise is fine.

Upvotes: 1

akond
akond

Reputation: 16060

Atoms were designed to solve exactly this problem:

Internally, swap! reads the current value, applies the function to it, and attempts to compare-and-set! it in. Since another thread may have changed the value in the intervening time, it may have to retry, and does so in a spin loop.

So you are safe here as long as two threads don't use the same key for the map (:a :b :c).

Upvotes: 2

Related Questions