In Python __radd__
, __rsub__
, and friends are used as follows: Docs
These methods are called to implement the binary arithmetic operations (+
, -
, *
, @
, /
, //
, %
, divmod()
, pow()
, **
, <<
, >>
, &
, ^
, |
) with reflected (swapped) operands. These functions are only called if the left operand does not support the corresponding operation and the operands are of different types. For instance, to evaluate the expression x - y
, where y
is an instance of a class that has an __rsub__()
method, type(y).__rsub__(y, x)
is called if type(x).__sub__(x, y)
returns NotImplemented
.
Ruby does not have something exactly like this (nor this explicit); however ruby can perform a similar process using #coerce
to ensure interoperability with instances of other numeric classes.
Let's assume A
looks like this
class A
attr_reader :attr
def initialize(a)
@attr = a
end
def +(other)
other = other.attr if other.is_a?(A)
A.new(attr + other)
end
end
Usage:
a = A.new(12)
a + 2
#=> #<A:0x00007fb2942c7f38 @attr=14>
a + a
#=> #<A:0x00007fb294156eb0 @attr=24>
2 + a
#=> `+': A can't be coerced into Integer (TypeError)
In this case you want to be able to use Integer#+
with A
as an argument. To do this you need to define A#coerce
class A
def coerce(other)
[A.new(other), self]
end
end
a = A.new(10)
2 + a
#=> #<A:0x00007fb2942e55d8 @attr=12>
If you would rather 2 + a
return an Integer
you can change the Array
provided by coerce
def coerce(other)
[other,attr]
end
a = A.new(5)
2 + a
#=> 7
What happens here (in simplified terms) is Integer#+
will see if it can add itself with the instance of A
. Since it does not understand what an A
is it will then call the coerce
method and try the same message again with the return values.
It pseudo works like this
arg1 = 2
arg2 = A.new(12)
message = :+
begin
arg1.public_send(message,arg2)
rescue TypeError
arg1, arg2 = arg2.coerce(arg1)
retry
end