Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Clojure's atom swap! return the new value?

Tags:

clojure

Most atom operators return the previous value before the swap such as std::atomic::fetch_add in C++. It's natural to use atomic int as a global increasing id starting from 0. Why does Clojure's atom return the value which is swapped in?

(def global-counter (atom 0))
(defn next! [] (dec (swap! global-counter inc)))

Is there a better way to create a zero-based counter in Clojure?

like image 773
woodings Avatar asked Nov 10 '14 06:11

woodings


1 Answers

Counter question: Do you know why std::atomic::fetch_add returns the pre-transaction value? (I don't.)

Calling swap! peforms a transaction and returns its result. In a concurrent scenario, if it returned the pre-transaction value, the only deterministic way to get the transaction result would be to repeat the in-transaction application, e. g.

(def pre-tx (std-swap! global-counter inc))
(def tx-result (inc pre-tx))

Certainly, an opposite example could be made up for the pre-transaction value. However, in most cases (and your example case too - see below), the tx-result is the value relevant for further reference. This is why swap! was designed to return it directly. For different requirements, a ref is suitable (Unless using an atom is requirement, in which case you have to create your own spin-loop with compare-and-set!).

In your example,next! should return 1 on the first call and there is no reason to dec it as long as counting is the given example. Counting always starts with one: If you count one, your total count is 1. If next! ever returned 0 (imaginary) last! would return -1, an invalid total count.

like image 177
Leon Grapenthin Avatar answered Oct 31 '22 05:10

Leon Grapenthin