Feature #10570
closedAllow `+=` etc. to be methods
Description
In MRI, it is currently possible to create #+=
methods in C extensions and even +=
aliases for existing methods in Ruby source code. These methods are only callable via #send('+=', ...)
because the parser interprets a += b
as a = a + b
before the "operator method" is called. Thus, a += b
is currently equivalent to a = a.send('+', b)
rather than a.send('+=', b)
. This feature request is to allow and support <OP>=
methods, where <OP>
is any of Ruby's operators that can be defined as methods (e.g. #+
, #-
, etc).
A related feature request would be to allow #<attribute><op>=
methods in addition to the already supported#<attribute>=
methods. As it is now, foo.bar += x
is equivalent to foo.send('bar=', foo.send('bar').send('+', x))
, which requires that the return value of foo.bar
implements #+
and that foo
implements #bar=
. If this related feature were implemented, foo.bar += x would be equivalent to
foo.send('bar+=', x)`.
I guess this would be tricky to add in a backwards compatible way. What happens if #+=
is not defined for the would-be receiver? How would that condition be detected in a way that could fall back to the old default behavior?
What other possible complications could make this request impractical?
Updated by matz (Yukihiro Matsumoto) almost 10 years ago
- Status changed from Open to Rejected
a+=b
is a short hand form of a = a + b
by definition. It's fundamentally an assignment. Target of assignment (including += etc) is a variable, not an object. It cannot be implemented by a method.
For example, how can we define Integer#+=
?
Matz.
Updated by david_macmahon (David MacMahon) almost 10 years ago
Thanks for your thoughtful reply!
Yukihiro Matsumoto wrote:
a+=b
is a short hand form ofa = a + b
by definition. It's fundamentally an assignment. Target of assignment (including += etc) is a variable, not an object. It cannot be implemented by a method.
I agree that a = a + b
is fundamentally an assignment (and I'm not asking for an assignment operator :-)). I'm not sure that the definition of a += b
as a short hand form of a = a + b
is quite so fundamental. Definitions can be redefined.
What about a[i] = b
? That is (or at least looks like) a form of assignment that is already implemented as a method.
For example, how can we define
Integer#+=
?
Immutable classes would simply not define a +=
method. For example, we already have Fixnum#[]
without Fixnum#[]=
.
Dave
Updated by david_macmahon (David MacMahon) almost 10 years ago
David MacMahon wrote:
Yukihiro Matsumoto wrote:
For example, how can we define
Integer#+=
?Immutable classes would simply not define a
+=
method
...and the current behavior would be used for lvalues not implementing a +=
method. That's the tricky part I was referring to in the original post.
Dave
Updated by matz (Yukihiro Matsumoto) almost 10 years ago
Array#[]=
can be defined by alternation of elements of an array, which does not contain any assignment to variables. That's the reason that can be implemented by a method. In contrast, a += b
includes assignment in its semantic, especially in a language like Ruby that has uniform reference model (unlike languages like C++).
Besides that, replacing +=
etc by methods would slow down those assignments significantly. I don't want that neither.
Matz.
Updated by david_macmahon (David MacMahon) almost 10 years ago
Yukihiro Matsumoto wrote:
Array#[]=
can be defined by alternation of elements of an array, which does not contain any assignment to variables. That's the reason that can be implemented by a method. In contrast,a += b
includes assignment in its semantic, especially in a language like Ruby that has uniform reference model (unlike languages like C++).Besides that, replacing
+=
etc by methods would slow down those assignments significantly. I don't want that neither.
Fair enough, but then what about #<attr><op>=
methods? it seems like foo.bar += 1
could be similar to the a[i] = b
case because it is not assigning foo
itself. Instead it could alter an attribute of foo
by calling the #bar+=
method. I guess supporting that would create problems for existing code that expects the current behavior. I'll stop pursuing this now.
Thanks again,
Dave