Skip to content

Instantly share code, notes, and snippets.

@samaaron
Created February 2, 2012 22:17
Show Gist options
  • Save samaaron/1726148 to your computer and use it in GitHub Desktop.
Save samaaron/1726148 to your computer and use it in GitHub Desktop.
Clojure: swap-returning-prev! switch!
(defn switch!
"Sets the value of atom to new-val. Returns the previous value."
[atom new-val]
(let [old-val @atom
success? (compare-and-set! atom old-val new-val)]
(if success?
old-val
(recur atom new-val))))
(defn swap-returning-prev!
"Similar to swap! except returns vector containing the previous and new values
(def a (atom 0))
(swap-returning-prev! a inc) ;=> [0 1]"
[atom f & args]
(loop []
(let [old-val @atom
new-val (apply f (cons old-val args))
success? (compare-and-set! atom old-val new-val)]
(if success?
[old-val new-val]
(recur)))))
@technomancy
Copy link

Do you need an explicit loop here? Wouldn't recuring to the top of the function work?

@samaaron
Copy link
Author

samaaron commented Feb 2, 2012

Yep, you're absolutely correct :-)

However, how would you use recur in #'swap-returning-prev! - you can't call (apply recur atom f args)...

@technomancy
Copy link

ISTR that recur interacts with destructuring in surprising ways:

((fn [a & b]
   (if a
     (recur nil b)
     b)) 1 2 3) ; -> (2 3)

So apply isn't necessary.

@samaaron
Copy link
Author

samaaron commented Feb 2, 2012

That's scary. I think I might stick with the explicit loop in this case :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment