Atoms

The function passed to swap! may run multiple times under contention, so keep it pure (no side effects).

(def counter (atom 0))
@counter                                ; 0
(swap! counter inc)                     ; 1: applies a pure function atomically (retries on contention)
(swap! counter + 10)                    ; 11
(reset! counter 0)                      ; set directly
(compare-and-set! counter 0 5)          ; true
(swap-vals! counter inc)                ; [5 6]: old and new values
(reset-vals! counter 100)               ; [6 100]

;; Map state
(def app-state (atom {:users {} :next-id 1}))

(defn add-user! [name]
  (swap! app-state
         (fn [{:keys [next-id] :as state}]
           (-> state
               (assoc-in [:users next-id] {:id next-id :name name})
               (update :next-id inc)))))

(add-user! "Ana")
(add-user! "Bo")
(get-in @app-state [:users 2 :name])    ; "Bo"

;; Validators and watches
(def age (atom 30 :validator #(<= 0 % 150)))
;; (reset! age -1) ; throws IllegalStateException: Invalid reference state
(add-watch counter :logger
           (fn [key ref old new] (println "counter:" old "->" new)))
(swap! counter inc)                     ; prints "counter: 100 -> 101"
(remove-watch counter :logger)