I had a scenario arise today where I needed an iterator with similar
semantics as Enumerable#all?, but non-short-circuiting. We came up with
a fairly elegant solution (imho), so I thought I'd be a good rubyzen
and share
1) First... the standard #all? (short-circuits):
(1..5).all? { |i| puts i; i < 3 }
1
2
3
=> false
2) Non-short-circuiting version (injecting truth):
On 9/27/06, Ken Kunz <kennethkunz@gmail.com> wrote:
I had a scenario arise today where I needed an iterator with similar
semantics as Enumerable#all?, but non-short-circuiting. We came up with
a fairly elegant solution (imho), so I thought I'd be a good rubyzen
and share
I had a scenario arise today where I needed an iterator with similar
semantics as Enumerable#all?, but non-short-circuiting. We came up with
a fairly elegant solution (imho), so I thought I'd be a good rubyzen
and share
1) First... the standard #all? (short-circuits):
(1..5).all? { |i| puts i; i < 3 }
1
2
3
=> false
2) Non-short-circuiting version (injecting truth):
I had a scenario arise today where I needed an iterator with similar
semantics as Enumerable#all?, but non-short-circuiting. We came up with
a fairly elegant solution (imho), so I thought I'd be a good rubyzen
and share
1) First... the standard #all? (short-circuits):
(1..5).all? { |i| puts i; i < 3 }
1
2
3
=> false
2) Non-short-circuiting version (injecting truth):
Also, with #2, obviously your way works, but the &&= isn't neccesary, a && has the intended effect, since the result of the block is put in the accumulator. Again, it doesn't matter at all, I'm mostly just writing to avoid doing work.
I had a scenario arise today where I needed an iterator with similar
semantics as Enumerable#all?, but non-short-circuiting. We came up with
a fairly elegant solution (imho), so I thought I'd be a good rubyzen
and share
Hmm, why Enumerable#all? without short circuit? If you get to a point where
the block doesnt apply, then you might aswell break.
The idea is that it's a case where you want the block to be executed,
unconditionally, once for every element in the array, and also want to
know whether at least one iteration returned false.
This approach is nice and concise... but I still prefer "truth
injection" for my actual code scenario. In my real code, the block is
multiple lines, and for clarity I don't love the idea of tacking a
method call on the end of a multi-line block.
Plus I just like saying "injecting truth"
... obviously your way works, but the &&= isn't neccesary ...
Also, with #2, obviously your way works, but the &&= isn't neccesary,
a && has the intended effect, since the result of the block is put in
the accumulator. Again, it doesn't matter at all, I'm mostly just
writing to avoid doing work.
In that case order should be reversed to avoid short circuiting altogether (in this case it does not matter as the test has no side effects, but if it had...)
Also, with #2, obviously your way works, but the &&= isn't neccesary,
a && has the intended effect, since the result of the block is put in
the accumulator. Again, it doesn't matter at all, I'm mostly just
writing to avoid doing work.
In that case order should be reversed to avoid short circuiting altogether (in this case it does not matter as the test has no side effects, but if it had...)
Very good point, neglected to think about that, glossing over the fact that the puts executing doesn't mean the relevant expression evaluated. With the fixed example:
irb(main):001:0> (1..5).inject(true) { |s,i| s &&= (puts i; i < 3) }
1
2
3
=> false
irb(main):002:0> (1..5).inject(true) { |s,i| s && (puts i; i < 3) }
1
2
3
=> false
irb(main):003:0> (1..5).inject(true) { |s,i| (puts i; i < 3) && s }
1
2
3
4
5
=> false
With the &&= vs && thing, I made a salient point about a bug in the example and I was too dumb to realize it.