I have this function:
(defn get-validator []
(UrlValidator. (into-array ["https"])))
I want it to be evaluated only once, on the first call, then just return the result. Which is the better way to write it:
(def get-validator (UrlValidator. (into-array ["https"])))
(def ^:const get-validator (UrlValidator. (into-array ["https"])))
(defonce get-validator (UrlValidator. (into-array ["https"])))
Or is there another way that is better? Documentation suggests that defonce
is the correct one, but it's not clearly stated.
First of all, def
sets a var with the given name and optionally the
given "init" value in that var, when the namespace is loaded/compiled
(note that there is basically not much of a difference between loading
and compiling and that's the reason, why you don't want to have
side-effects in your def
).
Roughly all three versions are the same, with the following differences:
:^const
allows inlining this value; so this effects the following
forms, when they are compiled and might improve performance in the
following codedefonce
prevents re-def-ining the var again once the namespace is
reloaded; this is most useful if you def
mutable state, that you
want to survive over reloading your codeIn any case, requiring the ns for the first time, will execute the code to init the var. Then it is basically left alone (imagine a static property in a Java class with a static initializer).
All that said: if UrlValidator
has internal state you might still be
better off using a function to create a fresh one, whenever you need it.