Execute time/CPU consuming functions outside and pass the calculated data inside as closure

Hello,

While studying Clojure and trying to understand closures, I wrote the following code snippets:

(defn calculate-how-to-end-sentence []
  (Thread/sleep 3000) ; just for test
  (str "!"))
  • first:
(defn create-greeting-function1
  [greeting]
  (fn [person-name]
    (str greeting " " person-name (calculate-how-to-end-sentence))))

(def greeting-friend1 (create-greeting-function1 "Hi"))

(def greeting-neighbour1 (create-greeting-function1 "Hello"))

(greeting-friend1 "Tom")
; "Hi Tom!"
(greeting-neighbour1 "Nancy")
; "Hello Nancy!"
  • second:
(defn create-greeting-function2
  [greeting]
  (let [end-of-line (calculate-something-that-takes-time)]
    (fn [person-name]
      (str greeting " " person-name end-of-line))))

(def greeting-friend2 (create-greeting-function2 "Hi"))

(def greeting-neighbour2 (create-greeting-function2 "Hello"))

(greeting-friend2 "Tom")
; "Hi Tom!"
(greeting-neighbour2 "Nancy")
; "Hello Nancy!"

It’s clear that if the calculate-how-to-end-sentence function always returns the same output (it’s pure function), it’s better to execute it outside of the (fn ...). In my example it would be even faster to (def end-of-sentence (calculate-how-to-end-sentence)) instead of calculating it inside let.

Could you please help me understand, when is the actual work (calculate-how-to-end-sentence calculation) done in case of the second function? I know it is not done when I run greeting-friend2. Which is good! But is it done when the program starts or when it is compiled?

Thanks!

calculate-something-that-takes-time should be run whenever create-greeting-function2 is invoked.

During normal program execution, it would happen when the namespace is loaded and the vars are initialized. At the REPL, it would also happen when the following forms are evaluated again

(def greeting-friend2 (create-greeting-function2 "Hi"))
(def greeting-neighbour2 (create-greeting-function2 "Hello"))

or even if you evaluated and discarded the returned function as in

(create-greeting-function2 "Hi")