I'm trying to understand what ^:const
does in clojure. This is what the dev docs say. http://dev.clojure.org/display/doc/1.3
(def constants {:pi 3.14 :e 2.71})
(def ^:const pi (:pi constants)) (def ^:const e (:e constants))
The overhead of looking up :e and :pi in the map happens at compile time, as (:pi constants) and (:e constants) are evaluated when their parent def forms are evaluated.
This is confusing since the metadata is for the var bound to symbol pi
, and the var bound to symbol e
, yet the sentence below says it helps speed up the map lookups, not the var lookups.
Can someone explain the what ^:const
is doing and the rationale behind using it? How does this compare to using a giant let
block or using a macro like (pi)
and (e)
?
That looks like a bad example to me, since the stuff about map-lookup just confuses the issue.
A more realistic example would be:
(def pi 3.14)
(defn circ [r] (* 2 pi r))
In this case, the body of circumference is compiled into code that dereferences pi at runtime (by calling Var.getRawRoot), each time circumference is called.
(def ^:const pi 3.14)
(defn circ2 [r] (* 2 pi r))
In this case, circ2
is compiled into exactly the same code as if it had been written like this:
(defn circ2 [r] (* 2 3.14 r))
That is, the call to Var.getRawRoot is skipped, which saves a little bit of time. Here is a quick measurement, where circ is the first version above, and circ2 is the second:
user> (time (dotimes [_ 1e5] (circ 1)))
"Elapsed time: 16.864154 msecs"
user> (time (dotimes [_ 1e5] (circ2 1)))
"Elapsed time: 6.854782 msecs"