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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With