Operator precedence for And/&& in Ruby

6.3k views Asked by At

I have a question regarding the and/&&/= keywords in Ruby.

The ruby docs say that the precedence for the mentioned keywords is: (1)&&, (2)=, (3)and.

I have this snippet of code I wrote:

def f(n) 
 n
end

if a = f(2) and  b = f(4) then  
    puts "1) #{a} #{b}" 
 end

if a = f(2) &&  b = f(4) then   
    puts "2) #{a} #{b}"     
end

The output is:

1) 2 4 [Expected]

2) 4 4 [Why?]

For some reason using the && causes both a and b to evaluate to 4?

5

There are 5 answers

0
Jörg W Mittag On BEST ANSWER

I don't quite understand the question you are asking. I mean, you have already given the answer yourself, before even asking the question: && binds tighter than = while and binds less tightly than =.

So, in the first case, the expression is evaluated as follows:

( a=f(2) )  and  ( b=f(4) )
( a=  2  )  and  ( b=f(4) )
      2     and  ( b=f(4) ) # a=2
      2     and  ( b=  4  ) # a=2
      2     and        4    # a=2; b=4
                       4    # a=2; b=4

In the second case, the evaluation is as follows:

a   =   (  f(2) && ( b=f(4) )  )
a   =   (    2  && ( b=f(4) )  )
a   =   (    2  && ( b=  4  )  )
a   =   (    2  &&       4     ) # b=4
a   =                    4       # b=4
                         4       # b=4; a=4
0
andrykonchin On

I do not know the specific rules that can help in this situation, but let's use the priorities of operations. Using the rules of priorities, we can divide the computation of the second expression on several steps

1 f(2) &&  b => expr1
2 expr1 = f(4) => expr2
3 a = expr2

Obvious that in Step 2 we get an incorrect situation - on the left side of = is rvalue - temporary object, which can not be assigning by any value. I assume that syntactic analyzer break the rules of priority evaluation of expressions when encounter such situations. More details on the calculations of expressions can be found here

0
Tim Sullivan On

From Programming Ruby 1.9:

The only difference in the two forms is precedence (and binds lower than &&).

0
Mondher Gatri On

if you modify your code like this you will get what you expect

def f(n) 
  n
end

if (a = f(2) and  b = f(4)) then  
  puts "1) #{a} #{b}" 
end

if (a = f(2)  and  b = f(4)) then   
  puts "2) #{a} #{b}"         
end

1) 2 4

2) 2 4

1
Pesto On

The reason is simple: precedence. As you say, the order is:

  1. &&
  2. =
  3. and

Since && has precedence over =, the statement is evaluated like this:

if a = (f(2) && (b = f(4))) then 

Which results in:

if a = (2 && 4) then

When x and y are integers, x && y returns y. Thus 2 && 4 results in a = 4.

For comparison's sake, the first one is evaluated like this:

if (a = f(2)) and  (b = f(4)) then