Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should the function the Clojure swap! is applied to be idempotent?

Tags:

clojure

swap

I am just going through Clojure Koans and I am now playing with atoms. My question is not related to Koans, but a general one.

Consider the following (shortened) example from Koans:

(def atomic-clock (atom 0))

(meditations
    (= 1 (do
        (swap! atomic-clock inc)
            @atomic-clock)))

The documentation for swap! states that the function it is applied to (inc in this case) could be called multiple times and thus the function should be free from side effect.

Obviously, inc is free from side effects, but is not idempotent. Does this mean, that the assertion above may actually still fail? I.e. that in the case the function is indeed called multiple times, the value of the atom is incremented more than once?

like image 800
ondrasek Avatar asked Dec 28 '13 18:12

ondrasek


1 Answers

The function passed to swap! may be called multiple times if there are multiple threads contending to modify the Atom. As long as it is free of side-effects, however, only the return of the final call will be reflected in the Atom's causal history.1

Here's one possible scenario:

  1. Thread 1 attempts (swap! atomic-clock inc).

  2. Thread 2 attempts the same.

  3. Thread 2 manages to perform its swap! first.

  4. Thread 1 attempts a compare-and-swap on the atom and fails, because its notion of the original value is now out of date.

  5. Thread 1 retries and successfully commits.

Here there are three calls to inc, two on thread 1, one on thread 2.

The fact that inc is not idempotent is not a problem.


1 Considered abstractly; Clojure does not actually store history information for Atoms.

like image 105
Michał Marczyk Avatar answered Oct 13 '22 05:10

Michał Marczyk