В Ruby, как реализовать 20-точка и точка-20 с помощью coerce()?

В Ruby операция

point - 20     # treating it as point - (20,20)
20 - point     # treating it as (20,20) - point

подлежат реализации.

Но следующий код:

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

Вывод:

#<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 the same as p - 30

30 - p фактически будет восприниматься функцией принуждения как p - 30. Можно ли заставить его работать?

Я действительно удивлен, что метод - не будет принуждать аргумент таким образом:

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

то есть функция возвращает negated version of a - b, а не просто возвращает a - b.


person nonopolarity    schedule 10.05.2010    source источник


Ответы (1)


Вычитание не является коммутативной операцией, поэтому вы не можете просто поменять местами операнды в своем coerce и ожидать, что это сработает. coerce(something) должно вернуть [something_equivalent, self]. Итак, в вашем случае, я думаю, вы должны написать свой Point#coerce следующим образом:

def coerce(something)
  if something.is_a?(Fixnum)
    [Point.new(something, something), self]
  else
    [self, something]
  end
end

Вам нужно будет немного изменить другие методы, но я оставлю это вам.

person Mladen Jablanović    schedule 10.05.2010
comment
Я думаю, что часть else неверна. В лучшем случае это не поможет, в худшем может вызвать бесконечный цикл. Если класс Point не знает, как заставить something, он должен поднять TypeError. - person Marc-André Lafortune; 11.05.2010
comment
Спасибо, согласен полностью. Я просто механически скопировал это как запасную логику. - person Mladen Jablanović; 11.05.2010