I'm trying to define a macro for defining compile-time constants syntax for which was added in Clojure 1.3:
== 2.14 ^:const defs ==
^:const lets you name primitive values with speedier reference.
(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.
Basically I want some syntax sugar around (def ^:const ... ...)
, so I'm trying to do it like this:
(defmacro defconst [const-name const-val]
`(def ^:const ~const-name ~const-val))
But this doesn't work:
user=> (macroexpand '(defconst pi 3.14))
(def pi 3.14)
From what I gather the #^<...>
meta shortcut is a reader macro, and to define a macro that adds some metadata to something, one should use (with-meta ...)
.
I haven't found any documentation regarding ^:const
. Does this syntactical construct even create some sort of metadata? Following example doesn't show any:
user=> (def ^:const pi 3.14)
#'user/pi
user=> (meta pi)
nil
The first issue is that you are examining the metadata of 3.14
. Use (meta (var pi))
to see the metadata of pi
. If you do, you will see that it includes :const true
.
(defmacro defconst [const-name const-val]
`(def
~(with-meta const-name
(assoc (meta const-name) :const true))
~const-val))
accurately reproduces the metadata and performance of ^:const
(the code is adapted from the source of defn-
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With