How do I call the original function when it is shaded by the binding?
I have a situation like this:
(defn a []
(do-something))
(defn b []
(let [original (a)]
(modify-original)))
(defn c []
(binding a b)
(a))
How can I "break the binding" and call a
in b
? I thought that a closure could handle a situation like this, so I wrote something similar to this, but it didn't work:
(defn c []
(let [original-a a
b (fn []
(let [original (original-a)]
(modify-original)))]
(b)))
Oh, I almost forgot: the code is much more complicated because it c
doesn't call directly b
. He called a subfunction in it that I cannot change. This is why I cannot use something like:
(defn ^:dynamic state [] (something))
source to share
If you want to always use the original value a
in a function b
, as you mentioned, you can grab the original a
into the function's environment b
(closure):
(defn ^:dynamic a []
(do-something))
(def b (let [a a]
(fn []
(let [original (a)]
(modify-original)))))
(defn c []
(binding [a b]
(a)))
Update . Or
(let [a a] (defn b []
(let [original (a)]
(modify-original))))
source to share
You can use java streams to "see through" bindings by creating and then grabbing the var value from a stream it is not bound on and leaving it in the var / atom / ref / etc variable, which can be found by code in the stream for which it is related:
user> (defn c []
(let [tmp-atom (atom nil)
original-a (do (doto (Thread. #(reset! tmp-atom a)) .start .join)
@tmp-atom)]
{:local-a a :original-a original-a}))
user> (c)
{:local-a 4, :original-a 4}
user> (binding [a 7] (c))
{:local-a 7, :original-a 4}
Or for a smaller example, first define the shared state bit and var to bind
user> (def result (atom ""))
#'user/result
user> (def ^:dynamic a 4)
#'user/a
in a stream without bindings, grab a which will get the root value of a:
user> (binding [a 5] (.start (Thread. #(reset! result (str "a was " a)))))
#<Thread Thread[Thread-77,5,main]>
user> result
#<Atom@7c75031f: "a was 4">
then compare that to working with the same code without a thread that uses the associated value a:
user> (binding [a 5] (reset! result (str "a was " a)))
"a was 5"
user> result
#<Atom@7c75031f: "a was 5">
user>
Most (all?) Conventional Clojure concurrency facilities try to push bindings to new threads to prevent this kind of situation.
putting this together:
source to share