Understanding Precedence of Assignment and Logical Operator in Ruby

Operator precedence of assignment and conditional operators

Higher precedence of assignment means that your expression evaluates to (x = 5) if false, and not to x = (5 if false). Note, that later is a perfectly valid expression too.

Whether each particular clause is executed is determined by language rules. E.g., in a ternary operator a ? b : c, only b or c will be executed, but not both.

edit
About the difference.

In x = (5 if false), assignment is processed first. But to complete it, we need left part of assignment, which is nil, because 5 if false evaluates to nil. So, the expression is equivalent of x = nil.

In (x = 5) if false, conditional operator is processed first. According to its rules, we first have to evaluate condition (false). Since it's false, there's nothing more to do and result of evaluation is nil.

Hope that's clear.

Is the assignment operator really just an operator?

From the doc: https://ruby-doc.org/docs/ruby-doc-bundle/Manual/man-1.4/syntax.html#assign

Assignment expression are used to assign objects to the variables or such. Assignments sometimes work as declarations for local variables or class constants. The left hand side of the assignment expressions can be either:

variables
variables `=' expression

On the right there is an expression, so the result of the expression is assigned to the variable.

So, you should look for expressions (*) before following the precedence.

1 && a = 3 are basically two "chained" expressions:

3 and 1 && 3

Maybe it is more readable as:
1 && a = 3 + 4 where the expressions are 3 + 4 and 1 && 7, see:

1 && a = 3 + 4 #=> 7
1 && 7 #=> 7
res = 1 && a = 3 + 4
res #=> 7

(*) The precedence table also helps to find the expression (Find the precedence table in the linked doc at the Operator expressions paragraph):

What's above the = in the table "forms" an expression to be assigned by =, what's below does not.

For example:

1 + 3 and 2 + 4 #=> 4
a = 1 + 3 and b = 2 + 4 #=> 4
(a = 1 + 3) and (b = 2 + 4) #=> 4
a = (1 + 3 and b = 2 + 4) #=> 6

You can also check these examples respect to the precedence table:

1 && 3 #=> 3
1 && a = 3 #=> 3
a #=> 3

3 and 1 #=> 3
3 and b = 1 #=> 3
b #=> 1

2 ** c = 2 + 1 #=> 8
c #=> 3

d = 2 ** 3
d #=> 8

e = 3
e **= 2
e #=> 9

Ruby operator precedence table

Ruby 2.1.0, 2.0, 1.9, 1.8

An operator is a token that represents an operation (such as addition or comparison) to be performed on one or more operands. The operands are expressions, and operators allow us to combine these operand expressions into larger expressions. (Ref)

N = arity = The number of operands the operator operates on. (Ref)

A = associativity = The order of evaluation when the same operator (or operators with the same precedence) appear sequentially in an expression. The value L means that expressions are evaluated from left to right. The value R means that expressions are evaluated from right to left. And the value N means that the operator is nonassociative and cannot be used multiple times in an expression without parentheses to specify the evaluation order. (Ref)

M = definability = Ruby implements a number of its operators as methods, allowing classes to define new meanings for those operators. Column M of specifies which operators are methods. Operators marked with a Y are implemented with methods and may be redefined, and operators marked with an N may not. (Ref)

The following table is ordered according to descending precedence (highest precedence at the top).

N A M  Operator(s)            Description
- - - ----------- -----------
1 R Y ! ~ + boolean NOT, bitwise complement, unary plus
(unary plus may be redefined from Ruby 1.9 with +@)

2 R Y ** exponentiation
1 R Y - unary minus (redefine with -@)

2 L Y * / % multiplication, division, modulo (remainder)
2 L Y + - addition (or concatenation), subtraction

2 L Y << >> bitwise shift-left (or append), bitwise shift-right
2 L Y & bitwise AND

2 L Y | ^ bitwise OR, bitwise XOR (exclusive OR)
2 L Y < <= >= > ordering

2 N Y == === != =~ !~ <=> equality, pattern matching, comparison
(!= and !~ may not be redefined prior to Ruby 1.9)

2 L N && boolean AND
2 L N || boolean OR

2 N N .. ... range creation (inclusive and exclusive)
and boolean flip-flops

3 R N ? : ternary if-then-else (conditional)
2 L N rescue exception-handling modifier

2 R N = assignment
2 R N **= *= /= %= += -= assignment
2 R N <<= >>= assignment
2 R N &&= &= ||= |= ^= assignment

1 N N defined? test variable definition and type
1 R N not boolean NOT (low precedence)
2 L N and or boolean AND, boolean OR (low precedence)
2 N N if unless while until conditional and loop modifiers

Difference between or and || in Ruby?

It's a matter of operator precedence.

|| has a higher precedence than or.

So, in between the two you have other operators including ternary (? :) and assignment (=) so which one you choose can affect the outcome of statements.

Here's a ruby operator precedence table.

See this question for another example using and/&&.

Also, be aware of some nasty things that could happen:

a = false || true  #=> true
a #=> true

a = false or true #=> true
a #=> false

Both of the previous two statements evaluate to true, but the second sets a to false since = precedence is lower than || but higher than or.

Difference between and and && in Ruby?

and is the same as && but with lower precedence. They both use short-circuit evaluation.

WARNING: and even has lower precedence than = so you'll usually want to avoid and. An example when and should be used can be found in the Rails Guide under "Avoiding Double Render Errors".

If || has higher precedence than =, then why does `a || a = b` work?

Precedence becomes an issue only when there is ambiguity in the expression. In case of:

 @var || @var = MyClass.new

there is no ambiguity. The assignment operator = makes sense only if there is a single variable on the left side of it (disregarding the complexities that arise from multiple assignment). It does not make sense to assign something to a variable called "@var || @var". Therefore, there is no ambiguity. The only way to interpret the above expression is to interpret it as:

 @var || (@var = MyClass.new)

Therefore, precedence is not an issue here.



Related Topics



Leave a reply



Submit