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

In Ruby, the operation of

    point - 20
    20 - point

are to be implemented.

But the following code:

    class Point

      attr_accessor :x, :y

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

      def -(q)
      if (q.is_a? Fixnum)
        return Point.new(@x - q, @y - q)
      end
        Point.new(@x - q.x, @y - q.y)
      end

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

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

      def coerce(something)
        [self, something]
      end

    end

    p = Point.new(100,100)
    q = Point.new(80,80)

    p (-p)

    p p - q
    p q - p

    p p * 3
    p 5 * p

    p p - 30
    p 30 - p

Output:

    #<Point:0x2424e54 @x=-100, @y=-100>
    #<Point:0x2424dc8 @x=20, @y=20>
    #<Point:0x2424d3c @x=-20, @y=-20>
    #<Point:0x2424cc4 @x=300, @y=300>
    #<Point:0x2424c38 @x=500, @y=500>
    #<Point:0x2424bc0 @x=70, @y=70>
    #<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:

    class Fixnum
      def -(something)
        if (/* something is unknown class */)
          a, b = something.coerce(self)
          return -(a - b) # because we are doing a - b but we wanted b
- a, so it is negated
        end
      end
    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/.

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

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)
   [Point.new(something, something), self]
end

* 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/
Github: rubyredrick (Rick DeNatale) · GitHub
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale