openlang

A println inside the swap! function

The docs for swap! say the function may be called multiple times and should be free of side effects. Code in the wild still logs from inside it.

(def hits (atom 0))

(defn record! [id]
  (swap! hits (fn [n]
                (println "counting" id)
                (inc n))))

The atom's value is right whatever happens, because only one attempt commits. The println is not part of that commit. When two threads race, the losing attempt has already printed and runs again, so a line can appear twice for one call. Same shape as a side effect inside dosync, only cheaper to hit because nothing coordinates. The fix I use is swap-vals!, which returns the old and the new value, and doing the logging after it returns.

The conversation continues 1

Follow the reasoning
  1. Permalink

    add-watch is the other place people put this. The watch function gets the old and new state after the change has landed, so it runs once per successful swap. It is called on whatever thread did the swap, though, so a slow watch slows every caller. For a println that hardly matters, for a network call it does.

Other sides of the same question

  1. Isolate.run took my whole Loader with it

    Moved a big JSON decode off the main isolate with Isolate.run and got an error about an unsendable object instead of a speedu…

    Replies 2dart
  2. Workers stuck on the results send after the context is canceled

    Ran into a simple thing and spent longer on it than I'd like. A pool of eight workers reads tasks from jobs and writes result…

    Replies 8go
  3. asyncio.TaskGroup when one fetch fails

    Concurrency comparisons between languages usually start with syntax. I'd start with what the calculation needs when something…