开发者

overloading an operator via a mixin

Is there a way to override a class's oper开发者_运维知识库ator, by creating a new operator method inside a module, then mixing that module into the class?

eg, this overrides Fixnum's + operator:

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

p 3 + 3

# => 9

This does not override Fixnum's + operator:

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

class Fixnum
  include NewOperators
end

p 3 + 3

# => 6


Your question led me to this interesting article which describes the problem:

Fixing Ruby’s Inheritance Model with Metamorph

This is the ultimate problem with Ruby’s inheritance model, in my opinion. Because mixins always take lower priority than methods defined directly in a class body, A#foo can not be overridden by mixin inclusion. Moreover, because mixins take lower priority than methods, A#foo is now violating encapsulation [...]

And his solution is to transparently define all new methods inside an anonymous inner module:

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, &block| meth.bind(self).call(*args, &block) }
    remove_method(name)
    include self::InstanceMethods
  end
end

This is also conveniently packaged in a library called metamorph, which allows you to have mixin methods override class methods by just requiring it.


No, because in a method lookup you don't get a chance to pull in methods that were defined in mixins or parent classes until you've actually looked at the current class.

That said, you can create a method that, when called on a class, will create methods in that class. This can give you a way to inject operators into classes easily.

Be warned that actually doing this is a good recipe for surprise. This is doubly true when you are changing standard modules whose behavior is relied upon by others. See http://avdi.org/devblog/2008/02/23/why-monkeypatching-is-destroying-ruby/ for context.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜