FeifanZ
FeifanZ

Reputation: 16316

Clojure string to symbol evaluates to wrong result

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

Answers (1)

Sam Estep
Sam Estep

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

Related Questions