Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constant definition in Clojure

Tags:

macros

clojure

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
like image 676
MisterMetaphor Avatar asked Feb 07 '12 14:02

MisterMetaphor


1 Answers

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-).

like image 188
Retief Avatar answered Nov 13 '22 21:11

Retief