How to inject code from one thread to another in Clojure?
I'm using Clojure with LWJGL and have implemented a game loop. I want to edit it interactively using the REPL. Consequently I have moved the loop and all OpenGL calls to a separate thread (using Java Runnables). I have has some success in changing the loop from the outside by: A. using atoms, accessible to both threads, and changing them from the REPL thread e.g. (:color @globals) and B. storing Clojure code as an atom (:code @globals)
, changing it from the REPL, and accessing it in the thread loop like so: (eval (:code @globals))
.
But Clojure's symbols are all bound to one thread. I can send a message to add 2 and two (+ 2 2)
, but it doesn't get much further than that.
As a LISP, Clojure has the code as data advantage. I want to leverage this to use my REPL thread to modify my graphics thread, but need to get around the symbol binding thing - how?
My loop:
(while (not (GLFW/glfwWindowShouldClose window))
(eval (:code @globals))
(GL11/glClearColor (get (:color @globals) 0) (get (:color @globals) 1)
(get (:color @globals) 2) (get (:color @globals) 3) )
......
)
You can pass your function as a value to the shared atom. There is no need to pass the raw Clojure code as data and eval it - you can just pass the function value:
(def my-function (atom (fn [])))
(.start
(Thread.
(fn []
(while true
(@my-function)
(Thread/sleep 1000)))))
(reset! my-function
(fn [] (println "A")))
;; wait a few seconds
;; prints 'A's with one second interval
(reset! my-function
(fn [] (println "B")))
;; prints 'B's with one second interval