For the interested, this is my (certainly pretty imperfect) solution for changing a value in a state map and returning the old and new value (that can be safely diffed to get the change):
(defn swap-in! "Combination of update-in and swap! returning the value at the path before and after." [atom path f & args] (loop [] (let [old-a @atom old-val (get-in old-a path) new-val (apply f (cons old-val args)) new-a (assoc-in old-a path new-val)] (if (compare-and-set! atom old-a new-a) [old-val new-val] (recur))))) ;; example: (swap-in! (atom {:k 1}) [:k] + 2) ;; => [1 3] 2014-03-21 0:57 GMT+01:00 Stephen Gilardi <scgila...@gmail.com>: > There was a stackoverflow question recently that requested a solution for > a similar problem: > > > https://stackoverflow.com/questions/22409638/remove-first-item-from-clojure-vector-atom-and-return-it > > One solution there is similar to this: > > (defn swap*! > "Like swap! but returns a vector of [old-value new-value]" > [atom f & args] > (loop [old-value @atom] > (let [new-value (apply f old-value args)] > (if (compare-and-set! atom old-value new-value) > [old-value new-value] > (recur @atom))))) > > This will return the correct old-value and new-value which you can diff. > > Another note: > > (swap! state #(update-in % [:teams] make-team)) > > > can be written more succinctly: > > (swap! state update-in [:teams] make-team) > > —Steve > > On Mar 20, 2014, at 6:28 PM, Jakub Holy <jakub.h...@iterate.no> wrote: > > I have couple of times run into a situation where I want to update a state > map held in an atom > and return the change, not the new value. I haven't found a good way to do > it so either I am missing > something obvious or there are more idiomatic ways to achieve what I need. > Could you advise me? > > A concrete example: In ma webapp I want to assign a unique random ID to > each user. Creating that ID is simple: > > (def state (atom {:teams {}})) > > ;; Remove already used IDs from a lazy seq of random IDs (=> unique), take > the 1st one > (defn unique-rand-id [id-set] > (first (remove id-set (repeatedly #(rand-int Integer/MAX_VALUE)))))) > > ;; Add a new team with a unique random ID to the teams map > (defn make-team [teams] > (let [id (unique-rand-id (set (keys teams)))] > (assoc teams id {}))) > > ;; Create a new team; TODO: How to get the new team's ID?! > (swap! state #(update-in % [:teams] make-team)) > > So I can generate and remember a new unique random ID but there is no way > to find out > what ID it was (I cannot just take diff of state before and after since > other threads could > have also added new IDs to it in the meanwhile.) > > Any advice is appreciated. Thank you! > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > > For more options, visit https://groups.google.com/d/optout. > > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to a topic in the > Google Groups "Clojure" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/clojure/2dHvX7bf7nA/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- *Forget software. Strive to make an impact, deliver a valuable change.* * (**Vær så snill og hjelp meg med å forbedre norsken **min –** skriftlig og muntlig. Takk!**)* Jakub Holy Solutions Engineer | +47 966 23 666 Iterate AS | www.iterate.no The Lean Software Development Consultancy - http://theholyjava.wordpress.com/ - -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.