Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling Clojure functions using var-quote syntax

Tags:

var

clojure

eval

Occasionally when looking at other people's Clojure code, I see a function defined via defn and then called using the var-quote syntax, e.g.:

user> (defn a [] 1)
#'user/a
user> (a)   ; This is how you normally call a function
1
user> (#'a) ; This uses the var-quote syntax and produces the same result
1

For the life of me I can't figure out the difference between these two ways of calling a function. I can't find anything in the evaluation documentation to say what happens when the operator of a call is a var that might suggest why the second form would be preferred. They both seem to respond in the same to binding assignments and syntax-quoting.

So, can somebody please provide a code sample that will illustrate the difference between (a) and (#'a) above?

Edit: I know that var-quote can be used to get to a var that's shadowed by a let lexical binding, but that doesn't seem to be the case in the code that I'm looking at.

like image 586
Alex Avatar asked Feb 07 '13 23:02

Alex


2 Answers

(#'a) always refers to the var a, while (a) can be shadowed by local bindings:

user> (defn a [] 1)
#'user/a
user> (let [a (fn [] "booh")] [(a) (#'a)])
["booh" 1]

But most actual uses of var-quote / function call are not calling the var-quote expression directly, but instead cache its value so that higher-order constructs refer to the current value of var a instead of its value when passed in:

(defn a [] 1)
(defn my-call [f] (fn [] (+ 1 (f))))
(def one (my-call a))
(def two (my-call #'a))
(defn a [] 2)

user> (one)
2
user> (two)
3

This is mostly useful for interactive development, where you're changing some function that gets wrapped in a bunch of other functions in other packages.

like image 155
Joost Diepenmaat Avatar answered Sep 28 '22 07:09

Joost Diepenmaat


The second form allows you to circumvent the privacy restrictions that clojure puts in place.

So, for instance, if you develop a library with private functions, but want to test them from a separate namespace, you cannot refer to them directly. But you can get to them using the var quote syntax. It's very useful for this.

Privacy is clojure is, in essence, a form of automatic documentation, as opposed to the privacy you see in Java. You can get around it.

user> (defn- a [] 1)
#'user/a
user> (ns user2)
nil
user2> (user/a)
CompilerException java.lang.IllegalStateException: var: #'user/a is not public,    compiling:(NO_SOURCE_PATH:1) 
user2> (#'user/a)
1
user2> 
like image 42
Phil Lord Avatar answered Sep 28 '22 07:09

Phil Lord