Operator precedence for And/&& in Ruby [duplicate]
Asked Answered
U

5

14

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?

Unshackle answered 3/12, 2009 at 15:12 Comment(0)
R
24

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
Retraction answered 3/12, 2009 at 16:15 Comment(0)
R
21

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 
Reinareinald answered 3/12, 2009 at 15:51 Comment(1)
What I don't understand in your example is why it wouldn't be evaluated as: if a = ( f(2) && b ) = f(4) thenLittlest
M
3

From Programming Ruby 1.9:

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

Mortgagee answered 3/12, 2009 at 15:18 Comment(0)
P
1

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

Pelaga answered 3/12, 2009 at 17:50 Comment(0)
R
-7

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

Rigorous answered 3/12, 2009 at 15:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.