When to use Var instead of function?

I go through the clojure development web book and she tells me to pass a handler (defined below) to the var object instead of the function itself, because the function will dynamically change (this is what the reboot does).

The book says:

โ€œPlease note that we must create var from the handler in order for this middleware to work. This is necessary to ensure that the Var object containing the current function handler is returned. If we used the handler instead, the application would only see the original value of the function. and the changes will not be reflected. " I really don't understand what this means, are they like vars?

(ns ring-app.core (:require [ring.adapter.jetty :as jetty] [ring.util.response :as response] [ring.middleware.reload :refer [wrap-reload]])) (defn handler [request] (response/response (str "<html>/<body> your IP is: " (:remote-addr request) "</body></html>"))) (defn wrap-nocache [handler] (fn [request] (-> request handler (assoc-in [:headers "Pragma"] "no-cache")))) 

Here is the call to the handler:

 (defn -main [] (jetty/run-jetty (wrap-reload (wrap-nocache (var handler))) {:port 3001 :join? false})) 
+7
clojure web var
source share
3 answers

Yes, var is like a C pointer. This is poorly documented.

Suppose you define fred as follows:

 (defn fred [x] (+ x 1)) 

There are actually three things. Firstly, fred is a symbol. There is a difference between the fred character (without quotes) and the keyword :fred (marked with a leading : char) and the string "fred" (marked with a double quote at both ends). For Clojure, each of them consists of 4 characters; that is, neither the colon of the keyword, nor the double quotation marks of the string are included in their length or composition:

 > (name 'fred) "fred" > (name :fred) "fred" > (name "fred") "fred" 

The only difference is how they are interpreted. The string is intended to represent user data of any type. The keyword is intended to represent control information for the program in readable form (unlike "magic numbers" such as 1 = left, 2 = right, we just use the keywords :left and :right .

The symbol should point to things like Java or C. If we say

 (let [x 1 y (+ x 1) ] (println y)) ;=> 2 

then x indicates the value 1, y indicates the value 2, and we see that the result is printed.

form (def ...) introduces an invisible third element, var . Therefore, if we say

 (def wilma 3) 

Now we have 3 objects. wilma is a character that points to a var , which in turn points to a value of 3 . When our program encounters a wilma character, it evaluates to find var . Similarly, var is evaluated to get a value of 3. Thus, this is similar to the bi-directional orientation of pointers in C. Since both characters and , var are "auto" evaluated, this happens automatically and invisibly, and you donโ€™t need to think about var (really , most people do not know that an invisible middle step even exists).

For our fred function above, a similar situation exists, except that var points to an anonymous function (fn [x] (+ x 1)) instead of 3 as wilma .

We can short-circuit the automatic evaluation of var as:

 > (var wilma) #'clj.core/wilma 

or

 > #'wilma #'clj.core/wilma 

where the reader macro #' (the pound quote) is a shorthand way to invoke a special form (var ...) . Keep in mind that a special form like var is an inline compiler, such as "if" or "def", and is not a regular function. The special form var returns a var object attached to the wilma symbol. clojure REPL prints the var object using the same shorthand, so both results look the same.

Once we have a var object, automatic evaluation is disabled:

 > (println (var wilma)) #'clj.core/wilma 

If we want to get the value that wilma indicates, we need to use var-get :

 > (var-get (var wilma)) 3 > (var-get #'wilma) 3 

The same thing works for fred:

 > (var-get #'fred) #object[clj.core$fred 0x599adf07 " clj.core$fred@599adf07 "] > (var-get (var fred)) #object[clj.core$fred 0x599adf07 " clj.core$fred@599adf07 "] 

where the material #object[clj.core$fred ...] is a clojure way of representing a function object as a string.

As for the web server, can it tell via the var? function var? or else, if the supplied value is a handler function, or var that points to a handler function.

If you type something like:

 (jetty/run-jetty handler) 

double automatic evaluation will give an object of the handler function, which is passed to run-jetty . If instead you enter:

 (jetty/run-jetty (var handler)) 

then var , which points to the handler function object, will be passed to run-jetty . Then run-jetty will have to use an if or equivalent to determine what it got and call (var-get ...) if it got var instead of a function. Thus, each time through (var-get ...) object to which var is currently pointing will be returned. Thus, var acts like a global pointer in C or a global "reference" variable in Java.

If you pass an object to a run-jetty , it saves a "local pointer" to the function object, and there is no way for the outside world to change what the local pointer refers to.

Here you can find more information:

+11
source share

Hope this little example helps you:

 > (defn your-handler [x] x) #'your-handler > (defn wrap-inc [f] (fn [x] (inc (fx)))) > #'wrap-inc > (def your-app-with-var (wrap-inc #'your-handler)) #'your-app-with-var > (def your-app-without-var (wrap-inc your-handler)) #'your-app-without-var > (your-app-with-var 1) 2 > (your-app-without-var 1) 2 > (defn your-handler [x] 10) #'your-handler > (your-app-with-var 1) 11 > (your-app-without-var 1) 2 

The intuition for this is that when you use var when creating your handler, you actually pass a "container" with some value, the contents of which can be changed in the future by specifying var with the same name. If you do not use var (for example, in your-app-without-var ), you pass the current value of this "container", which cannot be overridden in any way.

+7
source share

There are already some good answers. Just wanted to add this caveat:

 (defn f [] 10) (defn g [] (f)) (g) ;;=> 10 (defn f [] 11) ;; -Dclojure.compiler.direct-linking=true (g) ;;=> 10 ;; -Dclojure.compiler.direct-linking=false (g) ;;=> 11 

So, when the direct link is turned on, indirectness through var is replaced by a direct static call. Similar to the situation with the handler, but then with each var call, unless you explicitly reference var, for example:

 (defn g [] (#'f)) 
+7
source share