为什么ruby不支持方法重载?

velaa5lx  于 2022-12-26  发布在  Ruby
关注(0)|答案(9)|浏览(144)

Ruby不支持方法重载,而是覆盖现有的方法。有人能解释一下为什么语言是这样设计的吗?

k7fdbhmy

k7fdbhmy1#

“重载”这个术语在Ruby中根本没有意义。它基本上是“基于参数的静态调度”的同义词,但是Ruby根本没有静态调度。所以,Ruby不支持基于参数的静态调度的原因是因为它不支持静态调度,句号。它不支持任何类型的静态调度,不管是基于参数的还是其他类型的。
现在,如果您实际上“不是”专门询问重载,而是"动态“基于参数的调度,那么答案是:因为马茨没有实现它。因为没有人费心去提出它。因为没有人费心去实现它。
一般来说,在一种带有可选参数和可变长度参数列表的语言中,基于参数的动态调度是非常难以正确理解的,甚至更难以让人理解。即使在带有基于参数的静态调度而没有可选参数的语言中(例如Java),有时候对于一个凡人来说,要分辨出将要选择哪个重载几乎是不可能的。
在C#中,实际上可以将 * 任何 * 3-SAT问题编码为重载解析,这意味着C#中的重载解析是NP难的。
现在,尝试一下 dynamic dispatch,在这里,您需要在头脑中记住额外的时间维度。
有些语言基于过程的所有参数进行动态调度,而面向对象语言只在“隐藏的”第零个self参数上进行调度。例如,Common Lisp在所有参数的动态类型甚至动态值上进行调度。Clojure在所有参数的任意函数上进行调度(顺便说一句,这非常酷,也非常强大)。
但是我不知道有哪种OO语言支持动态的基于参数的分派,MartinOdersky说他 * 可能 * 会考虑在Scala中添加基于参数的分派。但是 * 只有 * 他能够同时移除重载 * 并且 * 与使用重载的现有Scala代码向后兼容并且与Java兼容(他特别提到了Swing和AWT,它们使用了一些极其复杂的技巧,几乎运用了Java相当复杂的重载规则的每一个令人讨厌的黑暗角落)。关于向Ruby添加基于参数的分派,我自己也有一些想法,但我从来没有弄清楚如何以向后兼容的方式来实现。

rpppsulh

rpppsulh2#

方法重载可以通过声明两个具有相同名称和不同签名的方法来实现。这些不同的签名可以是,
1.具有不同数据类型的参数,例如:第一个月
1.参数数量可变,例如:method(a) vs method(a, b)
我们不能用第一种方法实现方法重载,因为在ruby(动态类型语言)中没有数据类型声明,所以定义上述方法的唯一方法是def(a,b)
对于第二种选择,看起来我们可以实现方法重载,但实际上我们不能。假设我有两个参数数量不同的方法,

def method(a); end;
def method(a, b = true); end; # second argument has a default value

method(10)
# Now the method call can match the first one as well as the second one, 
# so here is the problem.

所以ruby需要在方法查找链中维护一个具有唯一名称的方法。

trnvg8h3

trnvg8h33#

我猜你正在寻找这样做的能力:

def my_method(arg1)
..
end

def my_method(arg1, arg2)
..
end

Ruby以不同的方式支持这一点:

def my_method(*args)
  if args.length == 1
    #method 1
  else
    #method 2
  end
end

一种常见的模式是将选项作为哈希值传入:

def my_method(options)
    if options[:arg1] and options[:arg2]
      #method 2
    elsif options[:arg1]
      #method 1
    end
end

my_method arg1: 'hello', arg2: 'world'
fnatzsnv

fnatzsnv4#

方法重载在使用静态类型的语言中是有意义的,在这种语言中可以区分不同类型的参数

f(1)
f('foo')
f(true)

以及在不同数量的参数之间

f(1)
f(1, 'foo')
f(1, 'foo', true)

第一个区别在Ruby中并不存在,Ruby使用动态类型或“鸭子类型”。第二个区别可以通过默认参数或使用参数来处理:

def f(n, s = 'foo', flux_compensator = true)
   ...
end

def f(*args)
  case args.size
  when  
     ...
  when 2
    ...
  when 3
    ...
  end
end
7fyelxc5

7fyelxc55#

这并没有回答为什么ruby没有方法重载,但是第三方库可以提供方法重载。
contracts.ruby库允许重载。示例改编自教程:

class Factorial
  include Contracts

  Contract 1 => 1
  def fact(x)
    x
  end

  Contract Num => Num
  def fact(x)
    x * fact(x - 1)
  end
end

# try it out
Factorial.new.fact(5)  # => 120

注意,这实际上比Java的重载更强大,因为您可以指定要匹配的值(例如1),而不仅仅是类型。
但是,您会发现使用此方法会降低性能;您必须运行基准来确定您可以容忍的程度。

cedebl8k

cedebl8k6#

我经常做以下结构:

def method(param)
    case param
    when String
         method_for_String(param)
    when Type1
         method_for_Type1(param)

    ...

    else
         #default implementation
    end
end

这允许对象的用户使用clean和clear method_name:但是如果他想优化执行,他可以直接调用正确的方法。
此外,它使您的测试更清晰和更好。

vatpfxk5

vatpfxk57#

关于为什么的问题已经有了很好的答案。但是,如果有人想要其他的解决方案,请 checkout functional-ruby Gem,它的灵感来自于Elixir pattern matching的特性。

class Foo
   include Functional::PatternMatching

   ## Constructor Over loading
   defn(:initialize) { @name = 'baz' }
   defn(:initialize, _) {|name| @name = name.to_s }

   ## Method Overloading
   defn(:greet, :male) {
     puts "Hello, sir!"
   }

   defn(:greet, :female) {
     puts "Hello, ma'am!"
   }
 end

 foo = Foo.new or Foo.new('Bar')
 foo.greet(:male)   => "Hello, sir!"
 foo.greet(:female) => "Hello, ma'am!"
fcwjkofz

fcwjkofz8#

我偶然看到了Ruby的创始人松本幸弘(Yukihiro松本,又名“Matz”)的精彩访谈。顺便说一句,他在访谈中解释了自己的推理和意图。这是对@nkm对这个问题的出色例证的一个很好的补充。我已经强调了回答你关于Ruby为什么要这样设计的问题的部分:
正交与和谐
比尔·文纳斯:Dave托马斯还声称**如果我让你添加一个正交的特征,你不会这么做。**你想要的是和谐的东西。这是什么意思?
松本幸弘:我相信一致性和正交性是设计的工具,而不是设计的主要目标。
比尔·文纳斯:正交性在本文中的含义是什么?
松本幸弘:正交性的一个例子是允许小特性或语法的任意组合。例如,C++既支持函数的默认参数值,也支持基于参数的函数名重载。这两种特性在语言中都是很好的特性,但是因为它们是正交的,所以可以同时应用这两种特性。编译器知道如何同时应用这两种特性。如果不明确,编译器会标记一个错误。但是如果我看代码,我也需要用我的大脑来应用这个规则。我需要猜测编译器是如何工作的。如果我是对的,我足够聪明,那就没有问题。但是如果我不够聪明,我真的不够聪明,它会引起混淆。结果对于普通人来说将是意想不到的这是正交性如何糟糕的一个例子。
资料来源:“Ruby的哲学”,与松本幸弘的对话,第一部分,比尔·文纳斯,2003年9月29日,网址:https://www.artima.com/intv/ruby.html

hof1towb

hof1towb9#

静态类型语言支持方法重载,这涉及到它们在编译时的绑定。另一方面,Ruby是一种动态类型语言,根本不支持静态绑定。在具有可选参数和可变长度参数列表的语言中,也很难确定在基于参数的动态调度期间将调用哪个方法。此外,Ruby是用C实现的,其本身不支持方法重载。

相关问题