簡體   English   中英

為什么 ruby​​ 不支持方法重載?

[英]Why doesn't ruby support method overloading?

Ruby 不支持方法重載,而是覆蓋現有方法。 誰能解釋為什么這種語言是這樣設計的?

“重載”是一個在 Ruby 中根本沒有意義的術語。 它基本上是“基於參數的靜態調度”的同義詞,但 Ruby根本沒有靜態調度。 所以,Ruby 之所以不支持基於參數的靜態分派,是因為它不支持靜態分派,句號。 它不支持任何類型的靜態調度,無論是基於參數的還是其他的。

現在,如果您實際上並沒有特別詢問重載,而是可能詢問基於動態參數的調度,那么答案是:因為 Matz 沒有實現它。 因為沒有其他人願意提出它。 因為沒有其他人費心去實現它。

一般來說,在具有可選參數和可變長度參數列表的語言中,基於動態參數的分派很難正確,甚至更難使其易於理解。 即使在具有基於靜態參數的分派且沒有可選參數的語言中(例如 Java),有時幾乎不可能告訴普通人將選擇哪個重載。

在 C# 中,您實際上可以將任何3-SAT 問題編碼為重載解決方案,這意味着 C# 中的重載解決方案是 NP 難的。

現在嘗試使用動態調度,您可以在其中保留額外的時間維度。

有些語言可以根據過程的所有參數動態分派,而面向對象的語言僅在“隱藏的”第零個self參數上分派。 例如,Common Lisp 調度動態類型,甚至所有參數的動態值。 Clojure 調度所有參數的任意函數(順便說一句,它非常酷且非常強大)。

但我不知道任何具有基於動態參數的調度的 OO 語言。 Martin Odersky 表示他可能會考慮在 Scala 中添加基於參數的調度,前提是他可以同時移除重載,並且與現有的使用重載的 Scala 代碼向后兼容並與 Java 兼容(他特別提到了 Swing 和 AWT它發揮了一些極其復雜的技巧,幾乎可以執行 Java 相當復雜的重載規則的每一個令人討厭的黑暗角落案例)。 我自己有一些關於向 Ruby 添加基於參數的調度的想法,但我永遠無法弄清楚如何以向后兼容的方式來實現它。

方法重載可以通過聲明兩個具有相同名稱和不同簽名的方法來實現。 這些不同的簽名可以是,

  1. 不同數據類型的參數,例如: method(int a, int b) vs method(String a, String b)
  2. 可變數量的參數,例如: 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​​ 需要在方法查找鏈中維護一個具有唯一名稱的方法。

我想你正在尋找這樣做的能力:

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'

希望有幫助

方法重載在具有靜態類型的語言中是有意義的,您可以在其中區分不同類型的參數

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

以及不同數量的參數之間

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

第一個區別在紅寶石中不存在。 Ruby 使用動態類型或“鴨子類型”。 第二個區別可以通過默認參數或使用參數來處理:

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


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

這並沒有回答為什么 ruby​​ 沒有方法重載的問題,但是第三方庫可以提供它。

contract.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 ),而不僅僅是類型。

但是,您會看到使用此功能會降低性能; 你將不得不運行基准來決定你能容忍多少。

我經常做以下結構:

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

    ...

    else
         #default implementation
    end
end

這允許對象的用戶使用干凈清晰的方法名:方法但是如果他想優化執行,他可以直接調用正確的方法。

此外,它使您的測試更清晰和更好。

關於問題的原因已經有了很好的答案。 但是,如果有人在尋找其他解決方案,請查看受 Elixir 模式匹配功能啟發的功能性紅寶石gem。

 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!"   

我遇到了對 Ruby 的創造者 Yukihiro Matsumoto(又名“Matz”)的精彩采訪。 順便說一句,他在那里解釋了他的推理和意圖。 這是對@nkm 對問題的出色示例的一個很好的補充。 我已經強調了回答你關於為什么Ruby 是這樣設計的問題的部分:

正交與和諧

Bill Venners:Dave Thomas 還聲稱,如果我要求你添加一個正交的特征,你不會這樣做。 你想要的是和諧的東西。 這意味着什么?

Yukihiro Matsumoto:我相信一致性和正交性是設計的工具,而不是設計的主要目標。

Bill Venners:在這種情況下,正交性意味着什么?

Yukihiro Matsumoto:正交性的一個例子是允許小特征或語法的任意組合。 例如,C++ 支持函數的默認參數值和基於參數的函數名重載。 兩者都是一種語言的好特性,但因為它們是正交的,你可以同時應用它們。 編譯器知道如何同時應用兩者。 如果它不明確,編譯器將標記一個錯誤。 但是如果我看代碼,我也需要用我的大腦來應用這個規則。 我需要猜測編譯器是如何工作的。 如果我是對的,而且我足夠聰明,那沒問題。 但如果我不夠聰明,而且我真的不夠聰明,就會引起混亂 結果對於一個普通人來說是出乎意料的。 這是正交性有多糟糕的一個例子。

資料來源:“Ruby 的哲學”,與 Yukihiro Matsumoto 的對話,Bill Venners 的第一部分,2003 年 9 月 29 日,網址: https ://www.artima.com/intv/ruby.html

靜態類型語言支持方法重載,這涉及到它們在編譯時的綁定。 另一方面,Ruby 是一種動態類型語言,根本不支持靜態綁定。 在具有可選參數和可變長度參數列表的語言中,也很難確定在基於動態參數的調度期間將調用哪個方法。 此外,Ruby 是用 C 實現的,它本身不支持方法重載。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM