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))

+3


source to share


2 answers


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))))

      

+4


source


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:
+1


source







All Articles