Question

I'm trying to find the idiomatic way to defer the initialization of a var (which I really intend to be immutable).

(def foo nil)
...
(defn init []
  ; (def foo (some-function))
  ; (set! foo (some-function)))

I know Rich Hickey said re-defing isn't idiomatic. Is set! appropriate here?

Was it helpful?

Solution

I would use delay:

Takes a body of expressions and yields a Delay object that will invoke the body only the first time it is forced (with force or deref/@), and will cache the result and return it on all subsequent force calls. See also - realized?

Example usage:

(def foo (delay (init-foo))) ;; init-foo is not called until foo is deref'ed

(defn do-something []
  (let [f @foo] ;; init-foo is called the first time this line is executed,
                ;; and the result saved and re-used for each subsequent call.
    ...
    ))

OTHER TIPS

Besides using delay as Alex states in his answer, set! works just fine because vars are just javascript variables under the hood.

Yous shouldn't really directly set! vars like this, but for special cases like this I personally allow myself to (sparingly) do so (ie the data actually is normal immutable Clojure once set up). One example where I do this is to override functions in debug builds:

(defn foo [] release code here)

Then in a file that is added only to debug builds:

(defn debug-foo []
  (.log js/console "foo called"))
(set! foo debug-foo)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top