It is said that when we have a class Point and knows how to perform
point * 3 like the following:

    class Point

      def initialize(x,y)
        @x, @y = x, y
      end

      def *(c)
        Point.new(@x * c, @y * c)
      end

    end

    point = Point.new(1,2)
    p point
    p point * 3

Output:

    #<Point:0x336094 @x=1, @y=2>
    #<Point:0x335fa4 @x=3, @y=6>

but then,

    3 * point

is not understood:

    Point can't be coerced into Fixnum (TypeError)

So we need to further define an instance method `coerce`:


    class Point
      def coerce(something)
        [self, something]
      end
    end

    p 3 * point

Output:

    #<Point:0x3c45a88 @x=3, @y=6>

So it is said that

    3 * point

is the same as

    3.*(point)

that is, the instance method `*` takes an argument `point` and invoke on
the object `3`.

Now, since this method `*` doesn't know how to multiply a point, so

    point.coerce(3)

will be called, and get back an array:

    [point, 3]

and then `*` is once again applied to it, is that true?

    point * 3

which is the same as

    point.*(3)

and now, this is understood and we now have a new Point object, as
performed by the instance method `*` of the Point class.

The question is:

1) who invokes point.coerce(3) ?  Is it Ruby automatically, or is it
some code inside of `*` method of Fixnum by catching an exception?  Or
is it by case statement that when it doesn't know one of the known
types, then call coerce?

2) Does coerce always need to return an array of 2 elements?  Can it be
no array?  Or can it be an array of 3 elements?

3) And is the rule that, the original operator (or method) `*` will then
be invoked on element 0, with the argument of element 1?  (element 0 and
element 1 are the two elements in that array returned by coerce)   Who
does it?  Is it done by Ruby or is it done by code in Fixnum?  If it is
done by code in Fixnum, then it is a "convention" that everybody follows
when doing a coerce?

So could it be the code in `*` of Fixnum doing something like this:

    class Fixnum

      def *(something)
      if (something.is_a? ...)
      else if ...  # other type / class
      else if ...  # other type / class
      else
      # it is not a type / class I know
        array = something.coerce(self)
        return array[0].*(array[1])   # or just return array[0] *
array[1]
      end
      end

    end

4) So it is really hard to add something to Fixnum's instance method
`coerce`?  It already has a lot of code in it and we can't just add a
few lines to enhance it (but will we ever want to?)

5) The coerce() in the Point class is quite generic and it works with
`*` or `+` because they are transitive.  What if it is not transitive,
such as if we define Point minus Fixnum to be:

    point = Point.new(100,100)
    point - 20       # ==> to give  (80,80)
    80 - point       # ==> to give  (-80,-80)
-- 
Posted via http://www.ruby-forum.com/.