Is the assignment operator really “just” an operator?

南楼画角 提交于 2020-08-22 04:57:25

问题


My question was triggered by this discussion on SO, which did not lead to an answer that would really explain the issue. I am "rewriting" it here in a slightly different way, because I want to make it more clear what the real problem is and therefore hope to get an answer here.

Consider the following two Ruby expressions:

  1. 1 * a - 3
  2. 1 && a = 3

From the Ruby precedence table, we know that of the operators mentioned here, * has the highest precedence, followed by -, then by && and finally by =.

The expressions don't have parenthesis, but - as we can verify in irb, providing a suitable value for a in the first case - they are evaluated as if the bracketing were written as (1*a) - 3, respectively 1 && (a=3).

The first one is easy to understand, since * binds stronger than -.

The second one can't be explained in this way. && binds stronger than =, so if precedence only would matter, the interpretation should be (1 && a) = 3.

Associativity (= is right-associative and - is left-associative) can't explain the effect either, because associativity is only important if we have several operators of the same kind (such as x-y-z or x=y=z).

There must be some special rule in the assignment operator, which I did not find in the docs I checked in particular the docs for assignment and syntax.

Could someone point out, where this special behaviour of the assignment operator is documented? Or did I miss / misunderstand something here?


回答1:


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



回答2:


Probably because the other interpretation does not work:

irb(main):003:0> (1 && a) = 3
Traceback (most recent call last):
        3: from /home/w/.rbenv/versions/2.7/bin/irb:23:in `<main>'
        2: from /home/w/.rbenv/versions/2.7/bin/irb:23:in `load'
        1: from /home/w/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/irb-1.2.3/exe/irb:11:in `<top (required)>'
SyntaxError ((irb):3: syntax error, unexpected '=', expecting `end')
(1 && a) = 3
         ^

So, perhaps Ruby parenthesizes 1 && a = 3 in the only way that is legally interpretable by the language.




回答3:


I think the understanding of 1 && (a = 3) is, understandably, mislead.

a = false
b = 1
b && a = 3
b
=> 1
a
=> 3

Why is a being assigned to in the && expression when a is false? Should the && expression not return when encountering a false value? Spoiler, it does return!

Taking a step back, we think of the purpose of the && operator to control the flow of logic. Our disposition to the statement

1 && a = 3

is to assume the entire statement is returned if a is nil or false. Well no, the interpreter is evaluating like so:

(1 && a) = 3

The interpreter does not raise a if it is nil or false nor does it return the left side if a is nil or false

a = nil
1 && a
=> nil # a was returned

The interpreter returns the variable, this is why the original statement can be read:

a = 3

due to 1 && a returning a which is a variable that can be assigned to by the = operand on the second half of the statement.

TLDR

In your origin example: 1 is neither nil nor false so the variable a is returned in (1 && a) which is subsequently assigned in a = 3



来源:https://stackoverflow.com/questions/63390971/is-the-assignment-operator-really-just-an-operator

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!