2010/5/10 Jian Lin <blueskybreeze / gmail.com>: > It is said that when we have a class Point and knows how to perform > point * 3 like the following: > > ¨Âìáóó Ðïéî> > ¨Âåæ éîéôéáìéú卸¬ù> ¨Âø¬ Àù ø¬ > ¨Âîä > > ¨Âåæ ª¨ã© > ¨Âïéîô®îå÷¨À㬠Àù ã© > ¨Âîä > > ¨Âîä > > ¨Âïéîô Ðïéîô®îå÷¨±¬²© > ¨Â ðïéî> ¨Â ðïéî> > Output: > > <Point:0x336094 @x=1, @y=2> > <Point:0x335fa4 @x=3, @y=6> > > but then, > > * point > > is not understood: > > ¨Âïéîô ãáî§âå ãïåòãåéîôï Æéøîõí ¨ÔùðåÅòòïò> > So we need to further define an instance method `coerce`: > > > ¨Âìáóó Ðïéî> ¨Âåæ ãïåòãå¨óïíåôèéîç> ¨ÂóåìæóïíåôèéîçÝ > ¨Âîä > ¨Âîä There is no type checking and conversion. Normally you would also return the argument first but in this case exchanging the order seems OK since the multiplication is not really symmetric. The std lib does it like this: irb(main):001:0> 1.2.coerce 3 => [3.0, 1.2] irb(main):002:0> Please see my blog post for a complete example: http://blog.rubybestpractices.com/posts/rklemme/019-Complete_Numeric_Class.html > The question is: > > 1) who invokes point.coerce(3) ? ¨Âéô Òõâù áõôïíáôéãáììù¬ ïò éó éô > some code inside of `*` method of Fixnum by catching an exception? ¨Â> is it by case statement that when it doesn't know one of the known > types, then call coerce? The latter. > 2) Does coerce always need to return an array of 2 elements? ¨Âáî éô âå > no array? ¨Âãáéô âå áî áòòáïæ åìåíåîôó It always needs to return an array of two elements - that's the contract. > 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) Exactly. >Who does it? ¨Âéô äïîå âù Òõâù ïò éó éô äïîå âù ãïäå éî Æéøîõí The latter. > ¨Âéô éó > done by code in Fixnum, then it is a "convention" that everybody follows > when doing a coerce? I'd rather say it's the contract of #coerce but you can call it a "convention" as well. > 4) So it is really hard to add something to Fixnum's instance method > `coerce`? ¨Âáìòåáäèáìïïæ ãïäå éî éô áî÷å ãáî§êõóô áä> few lines to enhance it (but will we ever want to?) You do not need to add to Fixnum's coerce. Rather you add to your operator implementation. > 5) The coerce() in the Point class is quite generic and it works with > `*` or `+` because they are transitive. ¨Âèáéæ éô éó îïôòáîóéôéöå> such as if we define Point minus Fixnum to be: > > ¨Âïéîô Ðïéîô®îå÷¨±°°¬±°°© > ¨Âïéîô ²° ½½ôï çéöå ¸°¬¸°© > 0 - point # ==> to give -80,-80) I think you confused "transitive" and "commutative". http://en.wikipedia.org/wiki/Commutative http://en.wikipedia.org/wiki/Transitive_relation Commutativity is the exact reason for having #coerce. Please see the blog post. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/