Ruby Method Overloading ·

栏目: IT技术 · 发布时间: 4年前

内容简介:Ruby doesn’t have such a feature. It was a shocking discovery when I switched from Java.. a very long time ago.We can somehow trick the language using optional and keyword arguments.

Method Overloading is a programming language feature that allows you to define multiple signatures (and implementations) of the same method.

Ruby doesn’t have such a feature. It was a shocking discovery when I switched from Java.. a very long time ago.

We can somehow trick the language using optional and keyword arguments.

But how can we have real isolated implementations of the same method? I wrote a hack to make this possible based on method arity.

class Foo
  include MethodOverloading

  def call
    puts "foo"
  end

  def call(number)
    puts "foo #{number}"
  end
end

foo = Foo.new
foo.call # => "foo"
foo.call(23) # => "foo 23"

Before I forget, don’t try this in a real-world project . :wink:

Method Definition in Ruby

When Ruby VM evaluates the body of a class, for each method definition, it invokes a special hook that allows you to interact with that method.

class Foo
  def self.method_added(method_name)
    super
    puts method_name
  end

  def call
  end
end

# => :call

Within that hook, you can have the full reference of the method starting from its name:

class Foo
  def self.method_added(method_name)
    super
    m = instance_method(method_name)
    puts m.arity
  end

  def call(number)
  end
end

# => 1

Method Registry

With the combination of method name and arity, you can build a registry of method definitions. These two pieces of information will act as a key, whereas the method itself will be the value.

class Foo
  @__method_overloading = {}

  def self.method_added(method_name)
    super
    m = instance_method(method_name)
    method_id = [method_name, m.arity]
    
    @__method_overloading[method_id] = m
  end

  def foo
  end

  def foo(number)
  end
end

Method undef

If you define multiple methods with the same name, Ruby will emit multiple warnings, and it will pick the last method definition.

You can take control of the method dispatching if you undefine the method in the method_added hook. By doing so, the class won’t reference the method anymore:

class Foo
  def self.method_added(method_name)
     super
     # store in the registry
     undef_method method_mame
  end

  def call
  end
end

Foo.new.call
# => NoMethodError

Method dispatching

You can use the almighty method_missing to check the method is in the registry, and execute it:

class Foo
  def self.respond_to_matching?(method_name, *args)
    @__method_overloading.key?([method_name, args.count])
  end

  def method_missing(method_name, *args, &blk)
    super unless self.class.respond_to_matching?(method_name, *args, &blk)

    self.class.matched_call(self, method_name, *args, &blk)
  end

  def respond_to_missing?(method_name, *)
    self.class.respond_to_method?(method_name)
  end
end

Unbound methods

There is one important detail to know: when a method is undefined, it will become an instance of UnboundMethod . That means it doesn’t have a context of execution anymore, because it has been removed from the class.

Using #bind_call and passing the context of execution (the instance of Foo ), Ruby VM will be able to “rebound” the context and correctly execute the method.

class Foo
  def self.matched_call(instance, method_name, *args, &blk)
    m = @__method_overloading.fetch([method_name, args.count]) { raise NoMethodError }
    m.bind_call(instance, *args)
  end
end

Performance

Because of the meta-programming and hand-crafted method dispatching, the code is ~14x slower than regular Ruby code. ‍♂️

Warming up --------------------------------------
  method overloading    24.146k i/100ms
              method   305.480k i/100ms
Calculating -------------------------------------
  method overloading    225.254k (±13.5%) i/s -      1.111M in   5.053180s
              method      3.274M (± 3.5%) i/s -     16.496M in   5.045562s

Comparison:
              method:  3273590.9 i/s
  method overloading:   225253.9 i/s - 14.53x  (± 0.00) slower

Conclusion

Ruby is such a fascinating and flexible language: if you can dream it, you can code it .

[ Complete implementation ]


很遗憾的说,推酷将在这个月底关闭。人生海海,几度秋凉,感谢那些有你的时光。


以上所述就是小编给大家介绍的《Ruby Method Overloading ·》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

iOS Web应用开发

iOS Web应用开发

皮基 (Andrea Picchi) / 罗晴明 / 人民邮电出版社 / 2013-8-1 / CNY 79.00

本书介绍了如何使用Web标准技术来为iPhone和iPad制作Web应用。书中利用最前沿的Web和移动技术,演示了如何使用HTML5来完成繁重的基础工作,如何使用CSS3来制作外观,以及如何使用JavaScript来为移动网站或Web应用添加程序逻辑。 通过阅读本书,读者可以掌握面向移动的项目的开发流程。作者逐章递进,引导读者了解iOS设计与开发的各个步骤。读者可以学习到如下知识: 设......一起来看看 《iOS Web应用开发》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

html转js在线工具
html转js在线工具

html转js在线工具