let suppose, I have var atom-var
(def atom-val (atom []))
Also suppose a standard behaviour of atom:
(swap! atom-val conj {:b "2"})
=> #object[clojure.lang.Atom 0x6500d3fd {:status :ready, :val [{:a "2"}]
(@atom-val)
=> #object[clojure.lang.Atom 0x6500d3fd {:status :ready, :val [{:a "2"}]
I want to create the same behaviour as it would work with nil object, but without actions:
(def atom-val nil)
(swap! atom-val conj "New val")
Of course, I will get a NullPointerException. But I want that nothing happened, supress it. I do not need to write try every time it, I just need the described behavuiour.
I see that swap! is a function, atom is a function, atom returns clojure.lang.IAtom, clojure.lang.IAtom is an interface. I cannot extend interface. How can I get the described behaviour?
Well, I have a global dynamic variable which is equal to nil
(def ^:dynamic atom-val nil).
Whenever a thread is created (it's ring handler with compojure), I am binding atom-val to
(defn func [handler]
(fn [request]
(binding [atom-val (atom [])]
(handler request)
)
)
So, I have such a form in different functions:
(swap! atom-val conj "New val").
I can run it everywhere lots of times (inside/outside different functions). It's really bad to check every time whether atom-val is null or not. Functions have to make swap!, but sometimes atom-val cannot be initialized properly (when a function makes swap! outside ring handlers, before binding).
So I decided to do it this way: I'd like to extend swap! protocol for Atom and when nil (when atom-val
is nil) is passed it mustn't throw NullPointerException.
If you want an atom that does nothing, you can write:
(def noop-atom
(reify clojure.lang.IAtom
(reset [_ _])
(swap [_ _])
(swap [_ _ _])
(swap [_ _ _ _])
(swap [_ _ _ _ _])
(compareAndSet [_ _ _])))
You can then use this atom as the root-value of the dynamic var.
If your goal is to manage state during the lifecycle of a Ring request/response, you can write a custom middleware.