Re: ruby, enum all? bug

Zach D. wrote:

Does anyone else think this is weird behavior in ruby 1.8.x ?
[].all?{ false } # => true

The implementation of enum.all? defaults the result to true, and then relies
on iterating over the elements to set it to false. It seems like it should

Daniel Parker wrote:

I agree, even though the docs do explain exactly what it does, it seems like
it shouldn’t return true. Maybe returning nil would be more appropriate when
there are no elements.

Craig D. wrote:

That the code does what the docs indicate is beside the point (though
it’s good that they’re in agreement :wink: ). The behavior is definitely
not what I would’ve expected, which is to return false. My vote is to
just return false when there are no elements. I like to avoid nil
whenever possible (which is almost always) because it forces client
code to use a conditional to check for it.

I guess I’m a contrarian here, because I think Ruby’s current behavior
is correct, and I think I can make a decent case for it. These kinds
of “edge” conditions can often be counter-intuitive, although if you
look at the larger picture they make perfect sense. Weren’t you a
little put off when you first learned that n**0 == 1 (if n != 0)? Or
when you learned that 0! == 1? But if powers and factorials didn’t
behave that way, a lot of simple stuff would break (like the formulas
for permutations and combinations).

First, the content of the block is irrelevant as it should never be
executed when the collection is empty. The block Zach uses though is
very well chosen, in that it really strikes his point home.

Second, all? (along with any?) are defined by the Enumerable module,
which is designed to with collections of various sorts, not just
arrays. All a collection has to do is implement the each method, and
Enumerable handles everything else. So the behavior of all? (and
any?) should make sense in this very general context – including
sets, trees, linked lists, etc.

Third, if all members of a collection have a property, then any
subset
of that collection should have that property. So if I have a
collection of accounts that are all overdue, any subset of those
accounts should be overdue as well, right? And the empty collection
is a valid subset.

[account1, account2, account3].all? { |a| a.overdue? }
=> true
[account1].all? { |a| a.overdue? }
=> true
[].all? { |a| a.overdue? }
=> true

If all? on an empty collection simply returns false, then we lose this
valuable property.

Fourth, there is a symmetry between all? and any?. In fact, it’s the
same symmetry we have between && and || using De Morgan’s Law:

P && Q == !(!P || !Q)
P || Q == !{!P && !Q)

With all? and any? we have these equivalents:

collection.all? { |member| member.property? } == ! collection.any? {
|member| ! member.property? } # note two inversions
collection.any? { |member| member.property? } == ! collection.all? {
|member| ! member.property? }

Let’s take accounts and being overdue as our specific example. If in
a given collection all accounts are overdue, then it can’t be the
case that *any *of the accounts are not overdue:

[account1, account2, account3].all? { |a| a.overdue? } == ! [account1,
account2, account3].any? { |a| ! a.overdue? } # note the two
inversions

Those expressions must be equivalent. And so should this:

[].all? { |a| a.overdue? } == ! [].any? { |a| ! a.overdue? } # note
the two inversions

Changing the behavior of all? would break this identity.

And note that just as:

[].all? { blah }

will always return true:

[].any? { blah }

will always return false.

So even though it seems counter-intuitive at first blush, in the
larger context it makes perfect sense, and it would be a mistake to
change it.

Eric

====

LearnRuby.com offers Rails & Ruby HANDS-ON public & ON-SITE workshops.
Ruby Fundamentals Workshop June 16-18 Ann Arbor, Mich.
Ready for Rails R. Workshop June 23-24 Ann Arbor, Mich.
Ruby on Rails Workshop June 25-27 Ann Arbor, Mich.
Ruby Plus Rails Combo Workshop June 23-27 Ann Arbor, Mich.
Please visit http://LearnRuby.com for all the details.

On Thu, Jun 12, 2008 at 7:54 PM, Eric I. [email protected] wrote:
I am surprised that some of you find it counterproductive that [].all?
always returns true.
IIRC that is one of the basic axioms or theorems of predicate logic,
any statement is true if applied to all members of the empty set.
But maybe I am wrong, anyway I am quite happy that Ruby does it the
way I learnt it in school :wink:

Cheers
Robert


http://ruby-smalltalk.blogspot.com/


As simple as possible, but not simpler.
Albert Einstein