Ruby Logical Operators

What's the difference between or and | in ruby?

The | operator is a binary mathematical operator, that is it does a binary OR and works on a numerical level:

1 | 2
# => 3
4 | 3
# => 7
1 | 2 | 3
# => 3

This is because it's manipulating individual values as if they were binary:

0b01 | 0b10
# => 3 (0b11)

The || operator is a logical one, that is it returns the first value that's logically true. In Ruby only literal nil and false values evaluates as logically false, everything else, including 0, empty strings and arrays, is true.

So:

1 || 2
# => 1
0 || 1
# => 0

The or operator works almost exactly the same as || except it's at a much lower precedence. That means other operators are evaluated first which can lead to some problems if you're not anticipating this:

a = false || true
# => true
a
# => true

a = false or true
# => true
a
# => false

This is because it's actually interpreted as:

(a = false) or true

This is because = has a higher precedence when being evaluated.

Logic OR / AND term evaluation order in Ruby

Ruby community commonly used is short-circuit evaluation which is && stands for AND, || stands for OR

It means in a conditional statement with two conditions the second condition is evaluated only when the first condition is not enough to determine the value of expression

so let's take an example for &&, ||

def a
puts 'a method'
false
end

def b
'b method'
true
end

a && b
# 'a method'
# => false

b is never evaluated

def a
puts 'a method'
true
end

def b
'b method'
false
end

a || b
# 'a method'
# => true

b is also never evaluated

there is another construction and, or (lowercased)

The and and or keywords serve the same purpose in Ruby. Properly understood, and and or are control flow operators, not boolean operators.

You use them as more like control-flow operators if, unless. This operations have very low operator precedence.

Further reading:

and or and short-curcuit difference

short-curcuit

Ruby logical operator

This is due to the strength of the operator binding, as operators are applied in a very particular order.

or is very loose, it has the lowest priority. The || operator is very strong, the opposite of that. Note how in that table || comes before =, but or comes after? That has implications.

From your example:

comp1 = a > 42 or b == 60

This is how Ruby interprets this:

(comp1 = (a > 42)) or (b == 60)

As such, the entire statement returns true but comp1 is assigned false because it doesn't capture the whole thing.

So to fix that, just use the strong binding version:

comp1 = a > 42 || b == 60
# => true

Ruby: difference between &= and &&=

Try the following:

x = 5
x |= 2
=> 7

|= and &= are equivalent to the bitwise x = x | 2 and x = x & 2

vs

x = 5
x ||= 2
=> 5

In the second statement, x ||= 2, it means x = 2 if x is nil, otherwise it's x.
( x = (x || 2) ; the expression x || 2 returns x if x is anything but nil otherwise it returns 2.

x ||= 'foo' is actually very common in Ruby (set x to foo is x is not already set)

x = (x & 3) (which is equivalent to x &= 3), returns 3 (the second operand) unless x is 0, it returns 0)
)

The same logic applies for & but it was easier to find an example on the top of my mind for |

=)

Difference between and and && in Ruby?

and is the same as && but with lower precedence. They both use short-circuit evaluation.

WARNING: and even has lower precedence than = so you'll usually want to avoid and. An example when and should be used can be found in the Rails Guide under "Avoiding Double Render Errors".

Need clarification on Ruby logical operators

As opposed to other languages like C, in Ruby all values except for nil and false are considered “truthy”. This means, that all these values behave like true in the context of a boolean expression.

Ruby's boolean operators will not return true or false. Instead, they return the first operand that causes the evaluation of the condition to be complete (also known as short-circuit evaluation). For boolean and that means, it will either return the first “falsy” operand or the last one:

false && 1    # => false     (falsy)
nil && 1 # => nil (falsy)
false && nil # => false (falsy)
1 && 2 # => 2 (truthy)

For boolean or that means, it will either return the first “truthy” operand or the last one:

false || 1    # => 1         (truthy)
nil || 1 # => 1 (truthy)
false || nil # => nil (falsy)
1 || 2 # => 1 (truthy)

This allows for some interesting constructs. It is a very common pattern to use || to set default values, for example:

def hello(name)
name = name || 'generic humanoid'
puts "Hello, #{name}!"
end

hello(nil) # Hello, generic humanoid!
hello('Bob') # Hello, Bob!

Another similar way to acheive the same thing is

name || (name = 'generic humanoid')

With the added benefit that if name is truthy, no assignment is performed at all. There is even a shortcut for this assignment of default values:

name ||= 'generic humanoid'

If you paid careful attention you will have noticed that this may cause some trouble, if one valid value is false:

destroy_humans = nil
destroy_humans ||= true
destroy_humans
#=> true

destroy_humans = false
destroy_humans ||= true
destroy_humans
#=> true, OMG run!

This is rarely the desired effect. So if you know that the values can only be a String or nil, using || and ||= is fine. If the variable can be false, you have to be more verbose:

destroy_humans = nil
destroy_humans = true if destroy_humans.nil?
destroy_humans
#=> true

destroy_humans = false
destroy_humans = true if destroy_humans.nil?
destroy_humans
#=> false, extinction of humanity digressed!

That was close! But wait, there is another caveat – specifically with the usage of and and or. These should never be used for boolean expressions, because they have very low operator precedence. That means they will be evaluated last. Consider the following examples:

is_human = true
is_zombie = false
destroy_human = is_human && is_zombie
destroy_human
#=> false

is_human = true
is_zombie = false
destroy_human = is_human and is_zombie
destroy_human
#=> true, Waaaah but I'm not a zombie!

Let me add some parentheses to clarify what's happening here:

destroy_human = is_human && is_zombie
# equivalent to
destroy_human = (is_human && is_zombie)

destroy_human = is_human and is_zombie
# equivalent to
(destroy_human = is_human) and is_zombie

So and and or are really just useful as “control-flow operators”, for example:

join_roboparty or fail 'forever alone :('
# this will raise a RuntimeError when join_roboparty returns a falsy value

join_roboparty and puts 'robotz party hard :)'
# this will only output the message if join_roboparty returns a truthy value

I hope that clarifies everything you need to know about these operators. It takes a bit of getting used to, because it differs from the way other languages handle it. But once you know how to use the different options, you've got some powerful tools at hand.

Combining logical operators in Ruby

Do as below using Enumerable#any?:

if [ones,twos,threes,fours,fives,sixes].any?{|e| e > 2 }
# do something
end

or as Jörg W Mittag suggested -

if [ones,twos,threes,fours,fives,sixes].any?(&2.method(:<))
# do something
end


Related Topics



Leave a reply



Submit