In Ruby, how does coerce() actually work?
Posted
by Jian Lin
on Stack Overflow
See other posts from Stack Overflow
or by Jian Lin
Published on 2010-05-09T23:26:42Z
Indexed on
2010/05/09
23:38 UTC
Read the original article
Hit count: 294
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 do something like this:
if (something.typeof? ...)
else if ... # other type
else if ... # other type
else
# if it is not a type I know
array = something.coerce(self)
return array[0].*(array[1])
end
© Stack Overflow or respective owner