Functions are objects implementing the IFn interface. This interface
defines a set of methods named "invoke" which return an object given
up to 21 arguments. Once the compiler is done emitting any given
function, an IFn object has been created. Def is a general operation
which creates a value and binds it to a var named by the current
(*ns*, symbol) pair. So for defn and an instance of this IFn object
is what the bound var points to. So as an example,
user=> (defn foo [x y] (+ x y 1))
; macroexpanded (def foo (fn* ([x y] (+ x y 1))))
#'user/foo
If you inspect the user namespace, you will find that the symbol foo
now maps to the var #'user/foo. Subsequent textual occurrences of
the symbol foo in this namespace will at compile time be mapped to
the var #'user/foo, and the emitted code will take the var
#'user/foo and dereference it to get an IFn object implementing the
foo function which can be invoked.
As there is overhead associated with dereferencing a var and some
code such as clojure.core/* is expected not to be redefined by
users, the ^:static annotation in Clojure 1.3 directed the compiler
to emit `public static invokeStatic` methods in addition to the
normal `public invoke` methods. This allowed potentially hot path
functions to statically invoke each other rather than using var
indirection. This static linking of function calls is how Oxcart
achieves the reported 24% speedup, and the linked direct branch is
Rich implementing invokeStatic again, presumably for Clojure 1.7.
This static linking feature was introduced in Clojure 1.3 and
removed in Clojure 1.4 because as I mentioned in my linked blog post
the downside of static linking is that live development and code
redefinition become harder or impossible. My expectation is that, as
1.7 is projected to introduce compilation profiles, this problem
will be mitigated by different builds or profiles of Clojure which
may enable or disable static linking in a user visible manner. So
for an application deployment build you may choose
[org.clojure/clojure "1.7.0-static"] which can use ^:static
annotations for a speedup while for development you may use
[org.clojure/clojure "1.7.0"] which may ignore ^:static in exchange
for a better REPL experience as Clojure 1.6 and 1.5 do.
Hope this helps,
Reid