Let's say I need to make a simple counter and I want counter to be incremented each time I call this function, but here is one unpleasant thing: defined 'counter' is not local and I can easily change its value from another space, that breaks encapsulation.
(defn next []
(defonce counter (atom 0))
(println @counter)
(reset! counter (inc @counter)))
Many say, it will be correct if I place 'private' meta tag. So function will look like this:
(defn next []
(defonce ^:private counter (atom 0))
(println @counter)
(reset! counter (inc @counter)))
But I still have access to 'counter' from another space.
Is there any way to implement this encapsulation or it's only at the agreement level?
Here's how you should write your next
function:
(def ^{:arglists '([])} next
(let [counter (atom 0)]
#(let [after (swap! counter inc)
before (dec after)]
(println before)
after)))
This is the same as the one in your question, except that it is thread-safe and completely encapsulates the counter
atom.