Share your thoughts in the 2021 Clojure Community Survey!

Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by

Is the following a known behaviour? Would love to know why is this the case. A hunch says recur at bytecode level is just a loop/jump so the code changes do not get reflected

(defn x
  []
  (recur))

(future (x))

(defn x
  []
  (println "reloaded")
  (recur)) ;; changes in fn (print statement) after reloading x does not get reflected in the recur variant which is still executing

(defn y
  []
  (y))

(future (y))

(defn y
  []
  (println "reloaded")
  (y)) ;; changes get reflected now

2 Answers

0 votes
by
selected by
 
Best answer

clj-java-decompiler shows basically this for function x:

public static Object invokeStatic() {
    while (true) {}
}

and this for y

public static final Var const__0;

public static Object invokeStatic() {
    return ((IFn)const__0.getRawRoot()).invoke();
}

That is the purpose of recur, to optimize self tail calls. y will run out of stack space at some point. So yes, a recur cannot be dynamically rebound.

0 votes
by

You can use vars to get the result that you expect.

(defn z 
  [idx]
  (prn [:z idx])
  (Thread/sleep 1000)
  (#'z (inc idx)))
(future (z 0))
;; [:z 0]
;; [:z 1]
;; [:z 2]
(defn z 
  [idx]
  (prn [:z :changed idx])
  (Thread/sleep 1000)
  (#'z (inc idx)))
;; [:z :changed 3]
;; [:z :changed 4]

"In java", it will do:

public static Object invokeStatic(Object idx) {
    prn(["z", idx ]);
    return ((IFn) RT.read("user/z")).invoke(idx + 1);
}
...