Search code examples
multithreadingconcurrencyclojureatomicclojurescript

How are Atoms implemented in Clojurescript?


In Clojure to address concurrency issues we can use an atom to write:

user=> (def my-atom (atom 0))
#'user/my-atom

user=> @my-atom
0

user=> (swap! my-atom inc)
1

user=> @my-atom
1

user=> (swap! my-atom (fn [n] (* (+ n n) 2)))
4

We know that this (in the Clojure implementation) is a wrapper around the Java Atomic object.

Interestingly enough, Atoms are replicated in ClojureScript, at a Syntactic level - even though JavaScript runtimes don't have an Atomic reference.

My question is, How are Atoms implemented in Clojurescript? Are they just an object Wrapper?


Solution

  • It just returns and assigns the value.

    In the source https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L4081

    (deftype Atom [state meta validator watches]
      ...
      IDeref
      (-deref [_] state) 
      ...)
    

    and https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L4110

    (defn atom
      "Creates and returns an Atom ..."
      ([x] (Atom. x nil nil nil))
      ([x & {:keys [meta validator]}] (Atom. x meta validator nil)))
    

    check the implementation of swap! and reset! you will find out:

    (set! (.-state a) new-value)

    then , go to https://github.com/clojure/clojurescript/blob/3bb97961cbc958aeaeac506222dc7b9dcb0e9fc1/src/clj/cljs/compiler.clj#L771 the set!, you will find the compiler just emits an 'assignment statement':

    (defmethod emit* :set!
      [{:keys [target val env]}]
      (emit-wrap env (emits target " = " val)))