1

In Ruby, it is reasonable to find code like:

a = 1 and b = 2 and c = 3
print "a = #{a}, b = #{b}, c = #{c}\n"

gets the result:

a = 1, b = 2, c = 3

but I cannot understand why code like:

a = 1 && b = 2 && c = 3
print "a = #{a}, b = #{b}, c = #{c}\n"

the result is:

a = 3, b = 3, c = 3

Could anyone please clarify that for me?

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
Huibin Zhang
  • 1,072
  • 1
  • 15
  • 30

2 Answers2

3

It's about higher precedence of && operator then and:

a = 1 && b = 2 && c = 3

is equivalent to

a = (1 and b = (2 and c = 3))

which results in

  1. 3 is assigned to c
  2. (2 and 3) which results in 3 is assigned to b
  3. (1 and 3) which results in 3 is finally assigned to a
David Unric
  • 7,421
  • 1
  • 37
  • 65
  • 1
    You don't explain why `2 && 3 == 3` – Borodin Sep 02 '13 at 23:32
  • @Borodin Logical ```and``` evaluates its right argument only if the left operand is evaluated to ```true``` Which is valid for any object except ```nil``` or ```false```. Right operand is then the result of the expression. But I don't think it need to be mentioned in an answer to OP's question. – David Unric Sep 02 '13 at 23:55
  • @Borodin Your insertion of inner-most parens in my answer find as quite redundant. – David Unric Sep 02 '13 at 23:58
  • @DavidUnric: Fair enough, it is your answer. But we are talking about operator precedence here, and I see no reason why `2 and c = 3` isn't equal to `(2 and c) = 3`. – Borodin Sep 03 '13 at 00:23
  • @DavidUnric: OK, so why does logical *and* *"evaluate its right argument only if the left operand is evaluated to true"*? – Borodin Sep 03 '13 at 00:26
0

Apart from the priority of the operands, this behaviour is the result of the short-circuit evaluation of logic operators.

When evauating and, if the first operand is found to be false, then there is no reason to evaluate the second. The value of a and b is therefore calculated as a ? b : a.

Likewise, the or operator contracts to a ? a : b.

These optimisations work fine logically, when we don't care about the specific value returned but only whether it is true or false. But it also allows for useful coding idioms, such as

( list = list || [] ) << item

which works because list = list || [] is evaluated as list = list (a no-op) if list is true (non-nil), or list = [] (creating a new empty array) if list has already been initialised, and so is "true".

So an expression like 2 and (c = 3) evaluates to 2 and 3 or 2 ? 3 : 2, so 3.

Borodin
  • 126,100
  • 9
  • 70
  • 144