# How to implement 20 - point and point - 20 using coerce()?

**URL:** <https://rubytalk.org/t/how-to-implement-20-point-and-point-20-using-coerce/58464>\
**Category:** ruby-talk\
**Created:** [10 May 2010 08:23 UTC](https://rubytalk.org/t/how-to-implement-20-point-and-point-20-using-coerce/58464 "2010-05-10T08:23:45Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jian\_Lin](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/jian_lin/32/1836_2.png) [@Jian\_Lin](https://rubytalk.org/u/Jian_Lin)\
**Post date:** [10 May 2010 08:23 UTC](https://rubytalk.org/t/how-to-implement-20-point-and-point-20-using-coerce/58464/1 "2010-05-10T08:23:45Z")

</div>

In Ruby, the operation of

&nbsp;&nbsp;&nbsp;&nbsp;point - 20  
&nbsp;&nbsp;&nbsp;&nbsp;20 - point

are to be implemented.

But the following code:

&nbsp;&nbsp;&nbsp;&nbsp;class Point

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;attr\_accessor :x, :y

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize(x,y)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@x, @y = x, y  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def -(q)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (q.is\_a? Fixnum)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Point.new(@x - q, @y - q)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Point.new(@x - q.x, @y - q.y)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def -@  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Point.new(-@x, -@y)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def \*(c)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Point.new(@x \* c, @y \* c)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def coerce(something)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[self, something]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;p = Point.new(100,100)  
&nbsp;&nbsp;&nbsp;&nbsp;q = Point.new(80,80)

&nbsp;&nbsp;&nbsp;&nbsp;p (-p)

&nbsp;&nbsp;&nbsp;&nbsp;p p - q  
&nbsp;&nbsp;&nbsp;&nbsp;p q - p

&nbsp;&nbsp;&nbsp;&nbsp;p p \* 3  
&nbsp;&nbsp;&nbsp;&nbsp;p 5 \* p

&nbsp;&nbsp;&nbsp;&nbsp;p p - 30  
&nbsp;&nbsp;&nbsp;&nbsp;p 30 - p

Output:

&nbsp;&nbsp;&nbsp;&nbsp;#\<Point:0x2424e54 @x=-100, @y=-100\>  
&nbsp;&nbsp;&nbsp;&nbsp;#\<Point:0x2424dc8 @x=20, @y=20\>  
&nbsp;&nbsp;&nbsp;&nbsp;#\<Point:0x2424d3c @x=-20, @y=-20\>  
&nbsp;&nbsp;&nbsp;&nbsp;#\<Point:0x2424cc4 @x=300, @y=300\>  
&nbsp;&nbsp;&nbsp;&nbsp;#\<Point:0x2424c38 @x=500, @y=500\>  
&nbsp;&nbsp;&nbsp;&nbsp;#\<Point:0x2424bc0 @x=70, @y=70\>  
&nbsp;&nbsp;&nbsp;&nbsp;#\<Point:0x2424b20 @x=70, @y=70\>

"30 - p" will actually be taken as "p - 30" by the coerce function. Can  
it be made to work?

I am actually surprise that the "-" method won't coerce the argument  
this way:

&nbsp;&nbsp;&nbsp;&nbsp;class Fixnum  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def -(something)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (/\* something is unknown class \*/)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a, b = something.coerce(self)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -(a - b) # because we are doing a - b but we wanted b  
- a, so it is negated  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end

that is, the function returns a "negated version of a - b" instead of  
just returning "a - b".

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

**Author:** ![Colin\_Bartlett1](https://avatars.discourse-cdn.com/v4/letter/c/dbc845/32.png) [@Colin\_Bartlett1](https://rubytalk.org/u/Colin_Bartlett1)\
**Post date:** [10 May 2010 10:39 UTC](https://rubytalk.org/t/how-to-implement-20-point-and-point-20-using-coerce/58464/2 "2010-05-10T10:39:42Z")

</div>

My apologies for the brevity and lack of explanation (I'm about to try  
to catch a train), but this might do the sort of thing that you want?  
(I think for coerce to work as you'd expect you need the operands(?)  
in the coerce array to be in the same order as in the calculation.  
Sorry if that doesn't make any sense! A fuller explanation will follow  
quite a bit later if you need one.)

class Point  
&nbsp;&nbsp;attr\_accessor :x, :y  
&nbsp;&nbsp;def initialize(x,y); @x, @y = x, y; end

&nbsp;&nbsp;def -(q)  
&nbsp;&nbsp;&nbsp;&nbsp;return Point.new(@x - q.x, @y - q.y) if q.kind\_of? Point  
&nbsp;&nbsp;&nbsp;&nbsp;Point.new(@x - q, @y - q)  
&nbsp;&nbsp;end

&nbsp;&nbsp;def \*(c); Point.new(@x \* c, @y \* c); end

&nbsp;&nbsp;def -@(); Point.new(-@x, -@y); end

&nbsp;&nbsp;def coerce(something); [Point::Coerce.new(something), self]; end  
end

class Point::Coerce  
&nbsp;&nbsp;attr\_reader :value

&nbsp;&nbsp;def initialize(v); @value = v; end

&nbsp;&nbsp;def \*(p)  
&nbsp;&nbsp;&nbsp;&nbsp;puts "Point::Coerce #{@value} \* #{p.inspect}"  
&nbsp;&nbsp;&nbsp;&nbsp;Point.new(@value \* p.x, @value \* p.y)  
&nbsp;&nbsp;end

&nbsp;&nbsp;def -(p)  
&nbsp;&nbsp;&nbsp;&nbsp;puts "Point::Coerce #{@value} - #{p.inspect}"  
&nbsp;&nbsp;&nbsp;&nbsp;Point.new(@value - p.x, @value - p.y)  
&nbsp;&nbsp;end  
end

p = Point.new(200,100)  
q = Point.new(80,70)  
puts  
p p, q  
puts  
p (-p)  
puts  
p p - q  
p q - p  
puts  
p p \* 3  
p 5 \* p  
puts  
p p - 30  
p 30 - p

---

<div class="post-metadata">

**Author:** ![Rick\_DeNatale1](https://avatars.discourse-cdn.com/v4/letter/r/bbce88/32.png) [@Rick\_DeNatale1](https://rubytalk.org/u/Rick_DeNatale1)\
**Post date:** [10 May 2010 11:49 UTC](https://rubytalk.org/t/how-to-implement-20-point-and-point-20-using-coerce/58464/3 "2010-05-10T11:49:56Z")

</div>

While this explains the usage of the coerce method well, I'm not sure  
that the answer to the original poster's question is mu\*

I may be wrong here, it's early and I haven't yet had a full cup of  
coffee, but while multiplication of a point (vector) and a scalar  
makes sense, I'm not sure that there is a conventional meaning to  
subtraction (or addition) of a scalar and a vector.

Colin's solution treats a scalar in this case as a unit point  
multiplied by the scalar. If this is what's wanted it can be done  
without the separate Point::Coerce class

def coerce(something)  
&nbsp;&nbsp;&nbsp;[Point.new(something, something), self]  
end

\* [http://en.wikipedia.org/wiki/Mu\_(negative)](http://en.wikipedia.org/wiki/Mu_(negative))

> **···**
>
> On Mon, May 10, 2010 at 6:39 AM, Colin Bartlett \<colinb2r@googlemail.com\> wrote:
> 
> > My apologies for the brevity and lack of explanation (I'm about to try  
> > to catch a train), but this might do the sort of thing that you want?  
> > (I think for coerce to work as you'd expect you need the operands(?)  
> > in the coerce array to be in the same order as in the calculation.  
> > Sorry if that doesn't make any sense! A fuller explanation will follow  
> > quite a bit later if you need one.)
> > 
> > class Point  
> > attr\_accessor :x, :y  
> > def initialize(x,y); @x, @y = x, y; end
> > 
> > def -(q)  
> > return Point.new(@x - q.x, @y - q.y) if q.kind\_of? Point  
> > Point.new(@x - q, @y - q)  
> > end
> > 
> > def \*(c); Point.new(@x \* c, @y \* c); end
> > 
> > def -@(); Point.new(-@x, -@y); end
> > 
> > def coerce(something); [Point::Coerce.new(something), self]; end  
> > end
> > 
> > class Point::Coerce  
> > attr\_reader :value
> > 
> > def initialize(v); @value = v; end
> > 
> > def \*(p)  
> > puts "Point::Coerce #{@value} \* #{p.inspect}"  
> > Point.new(@value \* p.x, @value \* p.y)  
> > end
> > 
> > def -(p)  
> > puts "Point::Coerce #{@value} - #{p.inspect}"  
> > Point.new(@value - p.x, @value - p.y)  
> > end  
> > end
> > 
> > p = Point.new(200,100)  
> > q = Point.new(80,70)  
> > puts  
> > p p, q  
> > puts  
> > p (-p)  
> > puts  
> > p p - q  
> > p q - p  
> > puts  
> > p p \* 3  
> > p 5 \* p  
> > puts  
> > p p - 30  
> > p 30 - p
> 
> --  
> Rick DeNatale
> 
> Blog: [http://talklikeaduck.denhaven2.com/](http://talklikeaduck.denhaven2.com/)  
> Github: [rubyredrick (Rick DeNatale) · GitHub](http://github.com/rubyredrick)  
> Twitter: @RickDeNatale  
> WWR: [http://www.workingwithrails.com/person/9021-rick-denatale](http://www.workingwithrails.com/person/9021-rick-denatale)  
> LinkedIn: [http://www.linkedin.com/in/rickdenatale](http://www.linkedin.com/in/rickdenatale)
