перегрузка оператора с помощью микширования

#ruby

#ruby

Вопрос:

Есть ли способ переопределить оператор класса, создав новый операторный метод внутри модуля, затем смешав этот модуль с классом?

например, это переопределяет оператор Fixnum :

 class Fixnum
  def  (x)
    product = x
    product = product * self
    return product
  end
end

p 3   3

# => 9
  

Это не переопределяет оператор Fixnum :

 module NewOperators
  def  (x)
    product = x
    product = product * self
    return product
  end  
end

class Fixnum
  include NewOperators
end

p 3   3

# => 6
  

Комментарии:

1. Это дубликат переопределяющего метода другим, определенным в модуле, и можете ли вы переопределить метод, включив модуль? плюс, я подозреваю, пара других. Короткий ответ таков: нет, вы не можете переопределять методы в подклассе методами в суперклассе, потому что наследование работает не так. Все с точностью до наоборот.

Ответ №1:

Ваш вопрос привел меня к этой интересной статье, в которой описывается проблема:

Исправление модели наследования Ruby с помощью Metamorph

На мой взгляд, это основная проблема с моделью наследования Ruby. Поскольку mixins всегда имеют более низкий приоритет, чем методы, определенные непосредственно в теле класса, #foo не может быть переопределен путем включения mixin. Более того, поскольку mixins имеют более низкий приоритет, чем методы, #foo теперь нарушает инкапсуляцию […]

И его решение заключается в прозрачном определении всех новых методов внутри анонимного внутреннего модуля:

 class Object
  def self.method_added(name)
    return if name == :initialize
    const_set(:InstanceMethods, Module.new) unless defined?(self::InstanceMethods)
    meth = instance_method(name)
    self::InstanceMethods.send(:define_method, name) {|*args, amp;block| meth.bind(self).call(*args, amp;block) }
    remove_method(name)
    include self::InstanceMethods
  end
end
  

Это также удобно упаковано в библиотеку под названием metamorph, которая позволяет вам использовать методы mixin для переопределения методов класса, просто требуя этого.

Ответ №2:

Нет, потому что при поиске метода у вас нет возможности использовать методы, которые были определены в mixins или родительских классах, пока вы на самом деле не посмотрите на текущий класс.

Тем не менее, вы можете создать метод, который при вызове в классе будет создавать методы в этом классе. Это может дать вам возможность легко внедрять операторы в классы.

Имейте в виду, что на самом деле это хороший способ преподнести сюрприз. Это вдвойне верно, когда вы меняете стандартные модули, на поведение которых полагаются другие. Смотрите http://avdi.org/devblog/2008/02/23/why-monkeypatching-is-destroying-ruby / для контекста.

Комментарии:

1. Интересная статья! Я вижу, как обезьянье исправление вышло бы из-под контроля для больших проектов.