Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does truth && "string" return "string"

Let's say I have a something like

true && true #=> true

Which makes sense, so I try something like:

true && "dsfdsf" #=> "dsfdsf"

Which surprises me because often times I'll do something like if something && something and I always thought that that was evaluating to true and would return true. Further experimentation doing things like:

jruby-1.7.3 :009 > "ad" && "dsf"
 => "dsf" 
jruby-1.7.3 :010 > "ad" && "sdfd" && nil
 => nil 
jruby-1.7.3 :011 > "ad" && nil && "sdf"
 => nil 

makes it seem like Ruby returns either the last value if all are true or the first false value it finds. Why does it do this? and is this a correct mental model?

like image 203
Noah Clark Avatar asked Mar 28 '14 15:03

Noah Clark


2 Answers

Boolean operators in ruby are short-circuiting: if it is possible to determine the value of the expression from the left-hand argument, the right-hand argument isn't evaluated.

Therefore, a simpler mental model for evaluation of a boolean expression involving && is to consider first expressions involving only two operands: the left-hand operand is evaluated first; if the value of this operand is nil or false, the operand is returned and the right-hand operand isn't evaluated; if the left-hand operand is anything else, the right-hand operator is evaluated and its value is returned.

From this definition, it's clear that, as you note, expressions involving boolean operators don't return true or false, but simply a true value or a false value. It's worth noting that this doesn't make any difference in a context where a boolean expression is used only for its true-ness or false-ness.

Being the boolean operators left-associative, it's easy to determine the order of evaluation of an expression containing more than one operator, remembering that && has higher precedence than || (be careful however that and and or have the same precedence). Having done this, we can easily see that the value of the expression is the last evaluated element, i.e. the element that permits to determine the overall true-ness or false-ness of the expression.

In your examples (an expression composed only by && operators) the value of the expression is known as soon as the first false value is encountered, or after the last element has been evaluated as a true value; so, the last element evaluated will be the last element if all the elements preceding it are true valued, and the first false valued element if any is encountered.

You might wonder why the value of the expression isn't converted to true or false; actually, this kind of behavior can be used in idioms like

x = x || default

or the more brief

x ||= default

that is used to check if x is nil and, in that case, assign a default value to it.

like image 196
Alberto Moriconi Avatar answered Nov 14 '22 23:11

Alberto Moriconi


Yes, it returns the last evaluated value. You can convert boolean if you want:

2.0.0p247 :016 > a = "s"
 => "s" 
2.0.0p247 :017 > !!a
 => true 
2.0.0p247 :018 > !!("ad" && nil && "sdf")
 => false

But this is not a nice solution. Try to use boolean types instead.

like image 44
Jozsef NYITRAI Avatar answered Nov 14 '22 23:11

Jozsef NYITRAI