Mr. Z.
Mr. Z.

Reputation: 348

How does "or" work in Clojure?

Why does the second operation computes to false? Does the "or" argument function differently in clojure? If so, how should I write the operation so it computes to true regardless of where the 0 is in the argument?

(= (or 0 1) 0) ; true

(= (or 1 0) 0) ; false

Upvotes: 4

Views: 326

Answers (5)

Andriy Ivaneyko
Andriy Ivaneyko

Reputation: 22021

(or)(or x)(or x & next) - evaluates expressions one at a time, from left to right.

If form returns logical true value, or returns that value and doesn't evaluate any of the other expressions, otherwise it returns the value of the last expression or nil if last expression are falsy (Source: Clojure documentation ).

In first statement (= (or 0 1) 0) the (or 0 1) return 0 because it's is logical true( in clojure inly nil and false are falsy) then compare with 0 so result is true.

In second statement (= (or 1 0) 0) it returns 1 and compare it to 0 and returns false because they aren't equal.

Upvotes: 5

Thumbnail
Thumbnail

Reputation: 13473

You are testing logical values for equality. This is a code smell in most languages and worse in Clojure.

(or 0 1) ; 0
(or 1 0) ; 1

... since both 0 and 1 are logically true, and or returns its first logically true argument (or the last argument, if there is no true one). The only things that aren't true are nil and false (and its boxed form Boolean/FALSE).

The fact that or is a macro is incidental in this case.

Upvotes: 2

kawas44
kawas44

Reputation: 81

In Clojure nil and false are falsy, everything else is truthy.

If you want the result of the expression to be true when there is a zero in a list, you should test if some elements of the list are equal to zero. (some zero? [0 1])

Upvotes: 3

cfrick
cfrick

Reputation: 37008

or is no function - it is a macro. it expands to if calls and by that the rules of if truth apply: nil or false are flasey, everything else is truthy - including 0.

user=> (when 0 (println "true"))
true
nil

Your code expands to:

user=> (macroexpand '(or 1 0))
(let* [or__4238__auto__ 1] (if or__4238__auto__ or__4238__auto__ (clojure.core/or 0)))

So in short, or's generated code returns the first truthy argument -- or the last one.

So if you want to know, if your list there contains any zero use something more appropriate:

user=> (some zero? [1 2 3])
nil
user=> (some zero? [1 2 0])
true

Or in case the 0 there is a param too:

user=> (some #{0} [1 2 3])
nil
user=> (some #{0} [1 2 0])
0

Upvotes: 3

sampwing
sampwing

Reputation: 1268

or returns the first non-false value or false. So in your examples or will return the first number in the argument list, zero or otherwise.

Upvotes: 3

Related Questions