The following works:
((resolve (symbol "first")) [1 2 3])
;; => 1
Why is it wrong to think that,
((read-string "first") [1 2 3])
;; => nil
should work, but it doesn't? (I get nil
.)
The return value from (resolve (symbol "first"))
is probably the Var clojure.core/first
which gets applied to the arguments.
The return value from (read-string "first")
is the symbol first
which also gets applied to the arguments. But using a symbol as a function has a different meaning. The argument is expected to be a map and the returned value is the equivalent of doing (get a-map the-symbol)
.
Any type that implements the clojure.lang.IFn
can be in the function position. The reason why using a symbol as a function with a vector argument returns nil
instead of failing, lies in the implementation details of IFn
for the Symbol
type (in this particular case for the arity 1):
public Object invoke(Object obj) {
return RT.get(obj, this);
}
RT.get()
checks if obj
implements ILookup
and calls ILookup.valAt()
if it does. Clojure vectors do implement ILookup
but they expect an integer as the provided key and return nil
for anything else.
public Object valAt(Object key, Object notFound){
if(Util.isInteger(key))
{
int i = ((Number) key).intValue();
if(i >= 0 && i < count())
return nth(i);
}
return notFound;
}
public Object valAt(Object key){
return valAt(key, null);
}
Juan is correct:
(resolve (symbol "first")) => <#clojure.lang.Var #'clojure.core/first>
(read-string "first") => <#clojure.lang.Symbol first>
We can verify:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(dotest
(let [first-var (var clojure.core/first)
first-sym (symbol "first")]
(is= 1 (first-var [1 2 3])) ; automatically converted from a var => funciton by Clojure
(is= nil (first-sym [1 2 3]))))
Please also see this answer for more information on the double-indirection of a Clojure Var object.