Unexpected behavior from clojure.java.api.Clojure
I have been experimenting with the clojure.java.api
one introduced in Clojure 1.6.0 since I would like to import some Clojure functionality into my java project. Unfortunately, it doesn't behave the way I expect it to when I call conditional functions and and or from Java .
IFn and = Clojure.var("clojure.core", "and");
IFn or = Clojure.var("clojure.core", "or");
-- equivalent to (and true false) in clojure
and.invoke(true,false); --> returns true rather than false???
-- equivalent to (or true false) in clojure
or.invoke(true,false); --> returns null rather than true???
-- equivalent to (and true true) in clojure
and.invoke(true,true); --> returns true as expected
-- equivalent to (or true true) in clojure
or.invoke(true,true); --> returns null rather than true???
I can't believe this is a bug, so I suspect I'm missing something fundamental enough API related. Whatever the reason, it left me rather confused. If anyone can suggest an explanation, I would be very grateful.
Thank,
Mt.
source to share
and
and or
are macros, and the rules for evaluation are slightly different for them. For example, when at the Clojure REPL trying to evaluate and
throws CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/and, compiling:(NO_SOURCE_PATH:0:0)
.
There must be a way to use them via clojure.java.api.Clojure
though, but I haven't figured it out yet since macros need to be compiled to work.
The next best option I can think of is using eval
, but I'm not sure if this is what you want to do. On the other hand, why use and
/ or
when the old old &&
/ ||
Java operators exist ?
source to share
and
and or
are macros, not functions. They expect two or more forms (so clojure.lang.IPsistentList of characters or nested IPersistentLists, I think), which they expand into a combination of let*
and if
.
(clojure.walk/macroexpand-all '(and true false))
;returns:
(let* [and__3941__auto__ true]
(if and__3941__auto__
false
and__3941__auto__))
You might be better off doing clojure fn that uses and
and or
on your behalf. For example, to take them by collection:
(defn reduce-and [values]
(reduce #(and %1 %2) values))
(defn reduce-or [values]
(reduce #(or %1 %2) values))
source to share