[].all?{} and [].any?{} Behavior

2010/7/31 Rick DeNatale [email protected]:

course relies on the regular behavior. Or you forget the “require”
harmful to others, I think you should be able to write whatever code
you want to under the same philosophy, whether or not it’s harmful to
you.

I did not want to sound puritanical, just point out that certain
habits are likely to have negative impact over time. And of course I
do agree that everyone should write their code as they see fit.

  1. Since one of the most useful ways to learn anything in such a way
    that you remember and internalize it is to make a mistake and realize
    the consequences.

LOL

[].all? {|element| element != 3 } # => true
There may be a better name than non_vacuous_all? but I can’t think of one.

I’d rather stick with two method calls because it makes crystall clear
what’s happening. Also, you may first want to check for emptyness and
if else branch based on that knowledge (or the other way round). In
other words: often you may want to separate both checks

Here I completely disagree. Extracting commonly used code to a well
named method is an essential part of writing and maintaining code.

While this is true as a general statement, creating too many methods
with trivial behavior can have a detrimental effect on software
readability and maintainability. The reason is that by doing this you
create additioanl artifacts that need to be documented and understand
by a reader. If on the other hand the idiom “!x.empty? && x.all?
{…}” is seen you can directly understand the behavior from three
basic mechanisms (#empty?, && and #all?) without having to resort to
other documentation. Finding a proper name for the combined method
also needs some careful consideration (as you have shown below).

payments.inject { |sum, p| sum + p.price }

def sum(identity = 0, &block)
if block_given?
map(&block).sum(identity)
else
inject { |sum, element| sum + element } || identity
end
end

There is at least the point that there is no universal neutral element
and 0 had to be chosen as default here; it’s certainly the proper
value for many (most?) cases in practice but one should at least be
aware of this. If your collection contains strings you would need to
use “” as the neutral element (which strangely enough is called
“identity” here which to me sounds like the identity function which is
something different - but I’m nitpicking).

Following your argument, this is bad because you might want to use
inject and + separately.

No, that was not my point. My point was that for the same
collection you may want to separate the emptyness check and the any /
all check that you combine in a single method. If you combine both in
a single method you cannot evalute results separately (or rather you
cannot use that method if you need the results separately). This is a
common case if you want to provide user responses that are easier to
understand for a human being.

But having such methods doesn’t prevent you in the least from using
inject, +, empty?, any? or any other method used to implement a
slightly more abstract extracted method separately. It does help to
keep your code DRY and to make it more understandable overall since
you don’t have to re-understand the effect of the separate invocations
each time you encounter them, as long as you are careful and name the
abstraction in an ‘intention revealing’ way.

As I said above, I do not think that creating new methods makes code
more understandable in all cases.

And doing this also enables changing the implementation of the
abstraction without holistic changes to the code. Yes I know about de
Morgan’s rules (I have a CS degree granted by a 1970’s era Electrical
Engineering department).

The hint was intended for the OP. I never assumed you didn’t know De
Morgan’s rules.

Placing the implementation in an abstraction
allows you to do the math proofs/unit testing and refactoring to meet
particular non-functional requirements in one place, which is a good
thing.

Right.

That might be a tad long, but I’d rather have a longer but more
intention revealing name, and let one of the several editors I use
deal with keeping my keystroke count down.

I tend to prefer longer and more telling names as well. As you said,
modern environments provide plenty of utilities to deal with the nasty
typing gracefully.

Kind regards

robert

Hi –

On Mon, 2 Aug 2010, Hal F. wrote:

[].all? {|element| element != 3 } # => true
Sorry, hit send by accident.

How about ‘every?’ for the non-vacuous ‘all?’?

If we really need one, that is.

Or maybe “all?!” :slight_smile:

David


David A. Black, Senior Developer, Cyrus Innovation Inc.

The Ruby training with Black/Brown/McAnally
Compleat Philadelphia, PA, October 1-2, 2010
Rubyist http://www.compleatrubyist.com

On Sun, Aug 1, 2010 at 12:24 PM, Hal F. [email protected]
wrote:

one.

How about #appall? to imply that it is a pessimistic implementation of
#all?
:slight_smile:

Sorry, hit send by accident.

How about ‘every?’ for the non-vacuous ‘all?’?

If we really need one, that is.

Hal

What about redefining all? to accept an optional param for what to do
when
empty? It doesn’t change default behaviour, but lets you get your
preferred
behaviour out of it. (note this only works on 1.9, because of how procs
take
params in 1.8)

module Enumerable
old_all = instance_method(:all?)
define_method :all? do |emptyval=true,&block|
return emptyval if empty?
old_all.bind(self).call &block
end
end

require ‘test/unit’

class NewAllTest < Test::Unit::TestCase
def test_empty
assert ![].all?(false)
assert [].all?(true)
assert [].all?
end
def test_non_empty_no_block
assert ![ nil, true, 99 ].all?(true)
assert ![ nil, true, 99 ].all?(false)
assert ![ nil, true, 99 ].all?
assert [ ‘’, true, 99 ].all?(true)
assert [ ‘’, true, 99 ].all?(false)
assert [ ‘’, true, 99 ].all?
end
def test_non_empty_block
assert [ 1, 3, 99 ].all?( true , &:odd? )
assert [ 1, 3, 99 ].all?( false , &:odd? )
assert [ 1, 3, 99 ].all?( &:odd? )
assert ![ 1, 2, 99 ].all?( true , &:odd? )
assert ![ 1, 2, 99 ].all?( false , &:odd? )
assert ![ 1, 2, 99 ].all?( &:odd? )
end
def test_non_array
assert Hash[*1…10].all? { |key,value| key.odd? && value.even? }
end
end

what about “all_and_not_empty” ?
or maybe: “all_and_when_I_say_all_I_say_all!” :smiley:

Hi –

On Tue, 3 Aug 2010, Josh C. wrote:

old_all.bind(self).call &block
end
end

You’re working a bit too hard there; you can just do:

module Enumerable
alias old_all all?
def all?(emptyval=true, &block)
return emptyval if empty?
old_all(&block)
end
end

with no need for the round trip to the method object and back.

But I think overall it might be even easier just to call empty? :slight_smile: I’m
also not a fan of Boolean arguments. I never remember what they mean.

David


David A. Black, Senior Developer, Cyrus Innovation Inc.

The Ruby training with Black/Brown/McAnally
Compleat Philadelphia, PA, October 1-2, 2010
Rubyist http://www.compleatrubyist.com

On Mon, Aug 2, 2010 at 5:12 PM, David A. Black [email protected]
wrote:

params in 1.8)

with no need for the round trip to the method object and back.

The Ruby training with Black/Brown/McAnally
Compleat Philadelphia, PA, October 1-2, 2010
Rubyist http://www.compleatrubyist.com

I did it that way based on the observations at this blog
Jay Fields' Thoughts: Ruby: Alias method alternative but
I
guess if you’re working by yourself, you will know you did it and not
have
collision issues, and if you’re working with a team, you would probably
not
be redefining Enumerable#all? so alias is probably a much better choice.

Hi –

On Tue, 3 Aug 2010, Josh C. wrote:

behaviour out of it. (note this only works on 1.9, because of how procs
end
end
be redefining Enumerable#all? so alias is probably a much better choice.
The blog post makes the motivation clearer to me – thanks. The
Enumerable#all example is (I hope :slight_smile: just hypothetical; I definitely
wouldn’t advocate overriding it at all.

David


David A. Black, Senior Developer, Cyrus Innovation Inc.

The Ruby training with Black/Brown/McAnally
Compleat Philadelphia, PA, October 1-2, 2010
Rubyist http://www.compleatrubyist.com