Search code examples
clojure

Update multiple elements of a Clojure atom within a single swap statement?


I have an atom that has two parts to it.

(def thing (atom {:queue '() :map {}}))

I want to update both :queue and :map in one atomic stroke, to prevent them from getting off-sync.

Queue individually:

(swap! thing update-in [:queue] (list 1))

(From this question: How to append to a nested list in a Clojure atom?)

Map individually:

(swap! thing assoc-in [:map 1] (:key :value))

(From this question: Using swap to MERGE (append to) a nested map in a Clojure atom?)

How can I do these both within a single swap statement? (assuming that would prevent them from getting off-sync?)


Solution

  • You have one change you want to make, right? And you could write that change as a pure function? All you need to do is write that function, and pass it as the argument to swap!.

    (defn take-from-queue [{q :queue, m :map}]
      {:queue (rest q), :map (assoc m :new-task (first q))})
    
    (swap! thing take-from-queue)
    

    Where of course I have no idea what you actually want the body of your function to do, so I've made up something that doesn't throw an exception.