If the function Clojure sweep! applied to idempotent?

I'm just reliving Clojure Coans, and now I'm playing with atoms. My question is not related to Coan, but a general one.

Consider the following (abbreviated) example from Koans:

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

Documentation for sharing! that the function that it applies to ( inc in this case) can be called several times, and therefore the function should be free of side effects.

Obviously, inc has no side effects, but is not idempotent. Does this mean that the above statement may actually still not work? That is, what if the function is actually called several times, the value of the atom increases more than once?

+6
source share
3 answers

Function passed to swap! , can be called several times if there are several threads associated with the modification of Atom. However, while it is free from side effects, only the return of the final call will be reflected in the history of the causality of the atom. 1

Here is one possible scenario:

  • Threads 1 try (swap! atomic-clock inc) .

  • Topic 2 is trying to do the same.

  • In thread 2, its swap! first executed swap! .

  • In thread 1, an attempt is made to compare and replace on an atom and is not performed because its original value is outdated.

  • Subject 1 retries and successfully completes.

There are three inc calls here, two on stream 1, one on stream 2.

The fact that inc not idempotent is not a problem.


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

+8
source

No, because the function will be called several times with the original value. If the swap succeeds, the function will not be called again with the new value that the function created. The repeated โ€œmay be causedโ€ situation is where the atom value has already been changed by another part of your program, so the exchange is repeated. As long as you return the same result for the same arguments, this is fine, but if, say, you read data from a stream and insert it into an atom, that would be problematic.

+1
source

No, this does mean that if you have more than one thread exchange per atom, the function may try again to use the correct value.

Follow these steps:

Thread1:

  • Read atomic-clock 0
  • inc atomic-clock
  • update atomic-clock with 1

Thread 2:

  • Read atomic-clock another 0
  • inc atomic-clock
  • update atomic-clock with 1 ==> WRONG should be 2

To call your function using the atom value, you need to read the current value.

But if the current value changes in another thread, the whole read / update process should try again, so your function is called again.

Assuming that if your function launches rockets, it will launch two rockets, even if the first time it is called from 0 and returns 1, and the second time it calls from 1 and returns 2.

+1
source

All Articles