Andy Harvey
Andy Harvey

Reputation: 12663

Why does .all? return true on an empty array?

Using Ruby I want to evaluate all items in an array, and return true if they all pass a conditional test.

I can do this using e.g. array.all? { |value| value == 2 }

So:

> array=[2,2]
> array.all? { |value| value == 2 }
=> true
> array=[2,3]
> array.all? { |value| value == 2 }
=> false

Great!

But, why does an empty array pass this test?

> array=[]
> array.all? { |value| value == 2 }
=> true

Shouldn't this return false?

And if I need it to return false, how should I modify the method?

Upvotes: 32

Views: 8023

Answers (10)

Radin Reth
Radin Reth

Reputation: 867

Make sure the array is not empty first. Then:

array.compact.present? && array.all? {|x| x != 2}

Upvotes: 0

Sachin Singh
Sachin Singh

Reputation: 7225

In Ruby you can never loop over an empty collection (array, hashes, etc.), so in your case your block never gets executed. And if the block never gets executed, all? returns true (there is no condition to make the result false).

Read about all? in the Ruby documentation.

You can simply achieve your goal by

  !array.empty? && array.all? { |value| value == 2 }

Upvotes: 11

kartik upadhyay
kartik upadhyay

Reputation: 162

The source of all? method says that it uses static variable(which is initially set to true) and then performs the AND operation between the static variable value and the result of the iteration finally returns this static variable as a result.

as the array is Empty ruby will never iterate on this empty array and as a result of this all? method will return the static variable which was set to true.

Upvotes: 0

Alistair A. Israel
Alistair A. Israel

Reputation: 6567

Just go

!(array.empty? || array.any? {|x| x != 2})

(Which has the added advantage of failing fast—that is, it can be evaluated properly without having to scan the whole array.)

Upvotes: 1

Amit Kumar Gupta
Amit Kumar Gupta

Reputation: 18577

This is a vacuous truth. It's the standard interpretation of a universal quantification, i.e. a

collection.all? { |x| some_predicate(x) }

over an empty collection, but it's known to strike people as counter-intuitive when they first see it in a formal setting. One nice way to think about why this is the preferred semantics is to think about how you would implement all?.

To make your test require that the array is non-empty, just do

array.any? && array.all? { |x| x == 2 }

Note that array.any? is fast no matter how large the array, whereas array.all? { |x| x == 2 } can be slow, depending on how big array is and how rare 2 is in it. So put the array.any? first.

Also note, there are degenerate cases where this won't work, for instance if array is [nil] or [false]. If cases like this might come up, replace array.any? with array.any? { true }.

Upvotes: 34

sawa
sawa

Reputation: 168169

As Amit Kumar Gupta writes, it is the standard interpretation of universal quantification. I have no idea why you expect it to be false. Here, you can see it should be true by inference.


Universal quantification is equivalent to conjunction, thus ("<=>" means equivalent):

"for all x in [a, b, c], P(x)" <=> "P(a) and P(b) and P(c)"

Notice that any proposition is equivalent to the conjunction of true and itself, so:

"for all x in [a, b, c], P(x)" <=> "true and P(a) and P(b) and P(c)"

If you lessen the elements in the set to two, you get:

"for all x in [a, b], P(x)" <=> "true and P(a) and P(b)"

and further to one element:

"for all x in [a], P(x)" <=> "true and P(a)"

Now, what happens with the empty set? Naturally,

"for all x in [], P(x)" <=> "true"


By noticing that existential quantification is equivalent to disjunction, you can also see that you should expect false with existential quantification over an empty set.

Upvotes: 0

Anand Shah
Anand Shah

Reputation: 14913

The documentation says : "The method returns true if the block never returns false or nil.." In the case of an empty array the block never executes and hence the method will always return true. As far as returning false is concerned you'll have to arr.empty?

Upvotes: 5

Boris Stitnicky
Boris Stitnicky

Reputation: 12578

Zeroes, empty collections, empty matrices and such have always been a bit special, if not outright problematic. Greeks knew well why they didn't count 0 among natural integers.

Method all? would be the first to ask you "why are you calling me on an empty array?" What do you mean by "all?", when there is nothing in there? That's a contradiction. And the method does short thinking, and answers true for the reasons outlined in the other three answers. Remember, you are at fault for talking about "all elements" of an empty array to begin with.

Upvotes: 0

scott_fakename
scott_fakename

Reputation: 10799

Since there is no item in the array that FAILS that test, it returns true. So just use somehting like:

array.size > 0 and array.all? { |value| value == 2}

Or something like that.

Upvotes: 0

David Hedlund
David Hedlund

Reputation: 129802

There is no item in that array that doesn't pass the test. I think you may need to throw in a test for array length.

Upvotes: 4

Related Questions