This is how assignment works; the return value is ignored, and the result of an assignment expression is always the right-hand value. This is a fundamental feature of Ruby's grammar. left-hand side = right-hand side
will always evaluate to right-hand side
, regardless of whether left hand side is a variable (x
), a method (object.x)
, a constant (X
) or any expression.
Source: Programming Languages | Ruby
IPA Ruby Standardization WG Draft, 11.4.2.2.5, Single method assignments
Consider chaining of assignments, x = y = 3
.
For this to work correctly, the result of y = 3
must be 3
, regardless of the actual value returned by the y=
method. x = y = 3
is meant to read as y = 3; x = 3
, not as y = 3; x = y
which is what would be implied if the return value from y=
was treated as the result of y = 3
.
Or consider all the other places assignment can be used. Sometimes, instead of this...
obj.x = getExpensiveThing()
if obj.x
...
... we write this ...
if obj.x = getExpensiveThing()
This couldn't work if the result of obj.x = ...
could be any arbitrary thing, but we know it will work because the result of obj.x = y
is always y
.
Update
A comment on the question states:
Interesting, I wasn't aware of this scenario. It seems that method= returns whatever input is given...
No, it's an important distinction to make. This has nothing to do with the return value of method assignment, and it definitely does not "return whatever input is given", it returns whatever you tell it to return.
The whole point is that the return value is ignored by the grammar of the language; assignment doesn't evaluate to the return value of the attr=
method, but the return value still exists as evidenced by the question itself: Example.new.send(:my_attr=, 5) # => 15
. This works because it is not assignment. You're side-stepping that part of the Ruby language.
Update again
To be clear: x
and y
in my examples shouldn't be interpreted as literal Ruby variables, they are place holders for any valid left-hand side of an assignment. x
or y
could be any expression: a
, obj.a
, CONSTANT_A
, Something::a
, @instance_a
, it's all the same. The value of assignment is always the right-hand side.