Reputation: 151076
In Ruby, it seems that a lot of coerce() help can be done by
def coerce(something)
[self, something]
end
that's is, when
3 + rational
is needed, Fixnum 3
doesn't know how to handle adding a Rational, so it asks Rational#coerce for help by calling rational.coerce(3), and this coerce instance method will tell the caller:
# I know how to handle rational + something, so I will return you the following:
[self, something]
# so that now you can invoke + on me, and I will deal with Fixnum to get an answer
So what if most operators can use this method, but not when it is (a - b) != (b - a) situation? Can coerce() know which operator it is, and just handle those special cases, while just using the simple [self, something] to handle all the other cases where (a op b) == (b op a) ? (op is the operator).
Upvotes: 1
Views: 442
Reputation: 44080
The point of coerce
is not to know what operation you are trying to perform. Its purpose is to bring the argument and self
to a common ground. Additionally, same operators can be commutative in certain classes, and not in other (Numeric#+
and Array#+
, for example), so your small commutativity-based coerce
exploit really won't pay off.
Instead of pushing your coerce
to do what it's not intended to, you should create a new class instead (such as ScalarPoint
, for example), and use it to interface scalar values with your Point
:
class ScalarPoint
attr_reader :val
def initialize(val)
@val = val
end
def +(arg)
case arg
when Point:
Point.new(@val + arg.x, @val + arg.y)
when ScalarPoint:
ScalarPoint.new(arg.val + @val)
else
raise "Unknown operand!"
end
end
# define other operators, such as * etc
def coerce(arg)
return [ScalarPoint.new(arg), self] if arg.is_a?(Numeric)
raise "Can't handle"
end
end
and
class Point
def coerce(arg)
[ScalarPoint.new(arg), self] if arg.is_a?(Numeric)
raise "Can't handle"
end
end
etc. (NB: code not tested)
Upvotes: 1
Reputation: 79572
The answer to this question is that you can know the operator by looking at the backtrace but you shouldn't do that.
That is not how the coerce mechanism of Ruby has been designed. As I answered in your previous question, coerce
should return two equivalent values [a, b]
such that a.send(operator, b)
will work, whatever the operator.
Upvotes: 1