On 5/10/10, Jian Lin <blueskybreeze / gmail.com> wrote:
> 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).

Coerce does not know the operator is being called on behalf of.

Here's how Rational#coerce is actually implemented. (This is from 1.8.
I think in 1.9 it was rewritten in c):

  def coerce(other)
    if other.kind_of?(Float)
      return other, self.to_f
    elsif other.kind_of?(Integer)
      return Rational.new!(other, 1), self
    else
      super
    end
  end

Generally, you want to return an array containing (a representation
of) other first and then (a representation of) self. That helps ensure
that when the caller calls
  other.op self
it won't end up with the arguments backwards. So operators like - and
/ can work correctly. If you return self first and then other, + and *
will work but, not - and /.