Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do all? and any? guarantee short-circuit evaluation?

Tags:

ruby

Testing out some code in both pry and irb, I get the following results:

[1] pry(main)> a = [1, 3, 5, 7, 0]
=> [1, 3, 5, 7, 0]
[2] pry(main)> a.any? {|obj| p obj; 3 / obj > 1}
1
=> true
[3] pry(main)> a.all? {|obj| p obj; 3 / obj > 1}
1
3
=> false

In [2] and [3] I see that there appears to be short-circuit evaluation that aborts the iteration as soon as possible, but is this guaranteed behaviour? Reading the documentation there is no mention of this behaviour. I realise that I can use inject instead as that will iterate over everything, but I'm interested in finding out what the official Ruby view is.

like image 758
Ken Y-N Avatar asked Dec 19 '13 06:12

Ken Y-N


People also ask

Does && use short-circuit evaluation?

Java's && and || operators use short circuit evaluation.

What is short-circuit evaluation?

Short-Circuit Evaluation: Short-circuiting is a programming concept in which the compiler skips the execution or evaluation of some sub-expressions in a logical expression. The compiler stops evaluating the further sub-expressions as soon as the value of the expression is determined.

Which operators perform short-circuit evaluation?

The Boolean AND and OR operators perform short-circuit evaluation, that is, they evaluate the expression on the right of the operator only when it is necessary to determine the overall result of the expression.


2 Answers

The any? method just realizes the 'or' logic function over the Enumerable. It could be interpreted as statement:

y = x1 v x2 v x3 v ... v xn

And the all? method realizes 'and' logic function over the Enumerable. It also could be interpreted as statement:

y = x1 * x2 * x3 * ... * xn

Since the Array is an Enumerable, it also includes those methods. So, for the method any? the first occurience of true (exactly neither nil nor false) result breaks enumeration with true result. In example the yielded becomes true on number 4, so the methods breaks the execution the returns true:

[1,2,3,4,5].any? {| x | puts x ; x > 3 }
# 1
# 2
# 3
# 4
# => true

Also you can apply DeMorgan's rule to the function any?, and to use all? method:

![1,2,3,4,5].all? {| x | puts x ; x <= 3 }
# 1
# 2
# 3
# 4
# => true

For the method all? the first occurience of either false or nil result do something similar, i.e. returns false. In example the yielded becomes false on number 3, so the methods breaks the execution the returns false:

[1,2,3,4,5].all? {| x | puts x ; x < 3 }
# 1
# 2
# 3
# => false

And with DeMorgan's transformation to use any? method:

![1,2,3,4,5].any? {| x | puts x ; x >= 3 }
# 1
# 2
# 3
# => false
like image 98
Малъ Скрылевъ Avatar answered Nov 04 '22 09:11

Малъ Скрылевъ


Yes.

In the final draft of the Ruby standard, all? is defined as such:

  1. Invoke the method each on the receiver
  2. For each element X which the method each yeilds:
    1. If block is given, call block with X as argument. If this call returns a falseish object, return false.
    2. If block is not given, and X is a falseish object, return false.
  3. Return true.

Note the word return in step 2. This guarantees short circuit evaluation. any? is defined similarly. However the standard is still a draft and I don't know which Ruby implementations (if any) aim to be standards-compliant.

like image 41
Max Avatar answered Nov 04 '22 08:11

Max