Reputation: 525
I couldn't help notice that the author prefers calling (first options)
multiple times over caching the result:
[docstring (if (string? (first options))
(first options)
nil)
options (if (string? (first options))
(next options)
options)
m (if (map? (first options))
(first options)
{})
options (if (map? (first options))
(next options)
options)
...]
I assume this is ok (in terms of performance) because it is defining a macro, which will be executed during compilation?
I'm still not sure if I understand the evaluation process of calling a macro. Using (defmulti ...)
as an example, correct me if I'm wrong: during compilation, the macro is expanded, of which the result is a call to the special let
form, which is in turn translated into bytecode. Then what?
Pretending we are defining a fn instead of a macro, is it worth it to introduce an extra symbol to cache the result of (first options)
:
[f (first options)
docstring (if (string? f)
f
nil)
options (if (string? f)
(next options)
options)
f (first options)
m (if (map? f)
f
{})
options (if (map? f)
(next options)
options)
...]
What exactly does it mean that a var hasRoot
? And what is an Unbound
?
Upvotes: 1
Views: 63
Reputation: 22415
Yes, calling first
is fast. The varargs are represented as a sequence, specifically a clojure.lang.ArraySeq
(at least up until a certain number of arguments).
user=> ((fn [& args] (type args)) 1 2 3)
clojure.lang.ArraySeq
The implementation of first()
on ArraySeq
is an array lookup
public Object first(){
if(array != null)
return array[i];
return null;
}
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ArraySeq.java#L69
Then the bytecode is then loaded into the JVM and executed.
I doubt that will make a difference.
A var can have thread-locale bindings, meaning it's possible for each thread to see a different value. The root binding is the value the var is initialized with. A thread-locale binding does not squash the root binding, it just shadows it. An Unbound
is a implementation optimization for vars that are created without a root binding.
Take a look at clojure.core/binding
for how to set thread-locale values.
Upvotes: 1