Skip to content
Atoms — Single-Cell Mutation
step 1/5

Reading — step 1 of 5

Learn

~1 min readManaged Mutation

Clojure values are immutable. Atoms wrap a value in a mutable container with thread-safe updates.

(def counter (atom 0))

@counter             ; deref — returns the current value: 0
(deref counter)      ; same

(swap! counter inc)  ; apply inc to current value: 1
(swap! counter + 5)  ; apply + with extra arg: 6
(reset! counter 100) ; replace value: 100

swap! runs your function on the current value and CAS-loops if another thread changed the atom in the meantime. The function MUST be pure — it might be retried.

Updating maps in atoms:

(def state (atom {:users {} :count 0}))

(swap! state update :count inc)
(swap! state assoc-in [:users "alice"] {:age 30})

update and assoc-in are functional map operations — return new maps, leave the original intact. The atom holds the new map atomically.

Watchers trigger callbacks on change:

(add-watch counter :log
    (fn [_key _atom old new]
        (println "counter changed" old "->" new)))

Atoms are the workhorse for Clojure state. Use them for:

  • Counters
  • Caches
  • Application configuration
  • In-memory databases

For coordinated multi-cell updates, use refs + STM. For uncoordinated async updates, use agents. Most code only needs atoms.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…