How can I / should I perform reverse operators in Ruby? For example, I have implemented the operator '+' for my object A so now A + 2 works well. Problem is: 2 + A does not work :( Python provides __radd__
to address this issue. How should I attack this issue with Ruby?
Do I have to override the '+' operator of Integer? How about if it is a float, do I have to override the '+' operator from Float too? I like Ruby more than Python (strictly a personal and subjective opinion) but in Python you can simply do:
def __radd__(self, other): # other + self
return self + other
Python provides __add__
and __radd__
that can be overridden. Does Ruby provide something similar?
Hoping that there is a quick and easy solution for that in Ruby, as 99.9% of the times there is.
Thanks!
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 expressionx - y
, wherey
is an instance of a class that has an__rsub__()
method,type(y).__rsub__(y, x)
is called iftype(x).__sub__(x, y)
returnsNotImplemented
.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With