Clojure caret as a symbol?

wrongusername picture wrongusername · Jan 19, 2012 · Viewed 7k times · Source

So I thought it would be a nice idea to name a function that calculates the exponential ^, but it seems like the caret actually does something special, as the Clojure REPL generates an error when evaluating '^. Googling mostly gave me this, so I was wondering what the actualy use for the caret in Clojure is.

(Also, would it be possible after all to name a function ^?)

Answer

Arthur Ulfeldt picture Arthur Ulfeldt · Jan 19, 2012

^ is "the meta character" it tells the reader to add the symbol starting with ^ as metadata to the next symbol (provided it is something that implements IMetas)

user=> (def x ^:IamMeta [1 2 3])
#'user/x
user=> x
[1 2 3]
user=> (meta x)
{:tag :IamMeta}
user=> 

You can learn a lot about how clojure works under the hood by looking at the meta of things, for instance functions:

user=> (meta foo)                          
{:ns #<Namespace user>, 
 :name foo, :file "NO_SOURCE_PATH", 
 :line 5, :arglists ([s])}

this is very often used for type hints

(defn foo [^String s] (.charAt s 1))

it is generally a good idea to turn on reflection warnings (set! *warn-on-reflection* true) and then add type hints until the warnings go away. without these Clojure will look up the type of the function operands at run-time, which saves you the trouble of fussing with types though at a slight cost.

PS: My next favorite reader character is the "dispatch" character #, it is well worth learning about it next :)

PPS: this is different in clojure 1.2.x vs clojure 1.3.x in Clojure 1.2.1 metadata does not compose when you use the meta-character:

user=> (def foo ^:foo ^:bar [1 2 3])
#'user/foo
user=> (meta foo)
{:tag :foo}

and in 1.3 it "does the right thing" and also keywords are options instead of "tags":

user=> (def foo ^:foo ^:bar [1 2 3])
#'user/foo
user=> (meta foo)
{:foo true, :bar true}