Yes for functions, because that only works for Vars pointing to functions, in that only Vars in function position will get recursively auto-dereferenced. If you use a var anywhere else, you get the Var and need to dereference it yourself:
(def a 10)
(def b #'a)
(+ 1 a) ;; 11
(+ 1 b) ;; Error
(+ 1 @b) ;; 11
(defn a [] 10)
(def b #'a)
(+ 1 (a)) ;; 11
(+ 1 (b)) ;; 11
(+ 1 (@b)) ;; 11
It also gets weird for macros, if you invoke them through the Var, you’re using them like functions, and need to pass the &env and &form as well:
(defmacro a [e] `(+ 1 ~e))
(a 2) ;; 3
(#'a 2) ;; Wrong arity
(#'a nil nil 2) ;; (clojure.core/+ 1 2)
And as you see, when used as a function it returns you the expanded code, instead of replacing the code by the returned code and returning the result of evaluating that.
That’s why for derived Vars that derive from a Var containing a value it is better to make it into a function:
(def a 10)
(defn b [] a)
(+ 1 a) ;; 11
(+ 1 (b)) ;; 11
(def a 11)
(+ 1 a) ;; 12
(+ 1 (b)) ;; 12
In that sense, wrapping in a function always works, it’ll work for values, for functions and for macros even, and I guess like @thheller said it seems a better convention in Clojurescript as well, though it comes down to personal preference, for functions adding #'
is definitely visually shorter and maybe more clear, but you need to remember to wrap in functions for values and macros.
It does, it’s one additional lookup each time, and I don’t believe it gets removed even if you use direct-linking.
I’d be curious to benchmark against wrapping in functions with direct linking turned on. The JIT does some function inlining, so I wonder if it could get rid of the indirection when optimizing for functions, but couldn’t for Vars.
I don’t think there is one that I know off.
Personally, I use #'
for functions and I just reload namespaces for everything else, and I never really expect people to pass in macros like that so never had to care. But now that you mentioned it, maybe I should consider changing my style to defaulting to wrapping in functions.
Also, for reloaded workflows, shout-out too: GitHub - aroemers/redelay: Clojure library for first class lifecycle-managed state. as a good solution for derived state at the REPL.
Edit: And I guess if you wanted to be fancy, you could have a macro that wraps in functions at dev time, but that just passes the thing as-is at prod time.