Reputation: 16316
user=> ((symbol "or") true false)
false
user=> (or true false)
true
Why does the first form evaluate to false
? I'd imagine the two input forms being equivalent.
Strangely, reversing the order of the arguments works:
user=> ((symbol "or") false true)
true
user => (or false true)
true
Upvotes: 2
Views: 58
Reputation: 13294
When you evaluate the list (or true false)
, Clojure first evaluates the first item. In this case, the first item is a symbol that names a macro, so Clojure expands the macro and evaluates the resulting data structure (which would be a let
form in this case).
On the other hand, when you evaluate the list ((symbol "or") true false)
, Clojure again first evaluates the first item, but in this case, the first item is another list! The first element of that list is the symbol symbol
, which names a function, so Clojure calls that function with the parameter "or"
, again producing the symbol or
. In other words, you are basically evaluating ('or true false)
.
Here's the catch: Clojure does not take that thing that it just evaluated and then go and evaluate it again. Rather, since it wasn't a symbol in the first place, Clojure evaluates it and then assumes that it must be a function. Is it a function? Indeed, the answer is yes!
user> (ifn? 'do)
;=> true
Here's where it gets a little tricky. The implementation of invoke
on the Symbol
class is the same as the implementation of invoke
on the Keyword
class: it assumes that the first argument is a map and tries to look itself up in that map. If you provide a second argument, it will use that as a default value.
Now, obviously, if you try to treat true
as a map and look up the symbol or
in that map, you'll find nothing. So Clojure helpfully returns the default value that you provided: false
. You could put any value you'd like in that second parameter spot, and as long as your symbol doesn't exist as a key in the first argument, you'll always get back your default value.
Upvotes: 5