Lars Melander
Lars Melander

Reputation: 529

Correct def for expression

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.

Upvotes: 0

Views: 131

Answers (2)

dorab
dorab

Reputation: 807

Another approach, assuming UrlValidator. is referentially transparent, is to use clojure.core/memoize.

So

(defn get-validator []
  (UrlValidator. (into-array ["https"])))
(def uval (memoize get-validator))

And then use (uval) whenever you need the validator. Because of the memoization, get-validator will be called only once.

This approach will make only one call to UrlValidator. the first time (uval) is executed. All the other suggestions will call UrlValidator., once, when the namespace is loaded.

Upvotes: 1

cfrick
cfrick

Reputation: 37073

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 code
  • defonce 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 code

In 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.

Upvotes: 3

Related Questions