簡體   English   中英

是什么讓Scala的運營商重載“好”,但是C ++的“糟糕”?

[英]What makes Scala's operator overloading “good”, but C++'s “bad”?

C ++中的運算符重載被許多人認為是壞事(tm),並且在新語言中不會重復錯誤。 當然,這是設計Java時專門刪除的一個功能。

現在我開始閱讀Scala,我發現它看起來非常像運算符重載(雖然從技術上來說它沒有運算符重載,因為它沒有運算符,只有函數)。 但是,它似乎與C ++中的運算符重載沒有本質上的區別,因為我記得運算符被定義為特殊函數。

所以我的問題是什么使得在Scala中定義“+”的想法比在C ++中更好?

C ++從C繼承了真正的藍色運算符。我的意思是6 + 4中的“+”非常特殊。 例如,您不能獲得指向該+函數的指針。

另一方面,Scala沒有這樣的運算符。 它在定義方法名稱和非字符號的一些內置優先級方面具有很大的靈活性。 所以從技術上講,Scala沒有運算符重載。

無論你想要什么,運算符重載本身並不壞,即使在C ++中也是如此。 問題在於糟糕的程序員濫用它。 但坦率地說,我認為剝奪程序員濫用運算符重載的能力並不能解決程序員可能濫用的所有問題。 真正的答案是指導。 http://james-iry.blogspot.com/2009/03/operator-overloading-ad-absurdum.html

盡管如此,C ++的運算符重載和Scala的靈活方法命名之間存在差異,恕我直言,這使得Scala不那么容易濫用和更容易被濫用。

在C ++中,獲取in-fix表示法的唯一方法是使用運算符。 否則,您必須使用object.message(參數)或指針 - > messsage(參數)或函數(argument1,argument2)。 因此,如果您希望代碼具有某種DSLish風格,那么使用運算符會有壓力。

在Scala中,您可以通過任何消息發送獲取中綴表示法。 “對象消息參數”完全沒問題,這意味着您不需要使用非單詞符號來獲取中綴表示法。

C ++運算符重載僅限於C運算符。 結合只有操作符可以使用的限制,這會給人們施加壓力,試圖將各種不相關的概念映射到相對較少的符號,如“+”和“>>”

Scala允許使用大量有效的非單詞符號作為方法名稱。 例如,我有一個嵌入式Prolog-ish DSL,你可以寫

female('jane)!         // jane is female
parent('jane,'john)!   // jane is john's parent
parent('jane, 'wendy)! // jane is wendy's parent

mother('Mother, 'Child) :- parent('Mother, 'Child) & female('Mother) //'// a mother of a child is the child's parent and is female

mother('X, 'john)?  // find john's mother
mother('jane, 'X)?  // find's all of jane's children

: - ,!,?和&符號被定義為普通方法。 僅在C ++中並且有效,因此嘗試將此DSL映射到C ++將需要一些已經引起非常不同的概念的符號。

當然,這也使Scala遭受了另一種虐待。 在Scala中,如果需要,可以將方法命名為$!&^%。

對於像Scala一樣靈活使用非單詞函數和方法名稱的其他語言,請參閱Smalltalk,其中,像Scala一樣,每個“運算符”只是另一種方法,Haskell允許程序員定義靈活命名的優先級和固定性功能。

許多人認為C ++中的運算符重載是壞事(tm)

只有無知。 在像C ++這樣的語言中絕對需要它,並且值得注意的是,其他開始采用“純粹主義”觀點的語言,一旦他們的設計師發現它有多么必要,就添加了它。

在C ++中,運算符重載從未被普遍認為是一個壞主意 - 只是濫用運算符重載被認為是一個壞主意。 一個人不需要語言中的運算符重載,因為無論如何它們都可以使用更詳細的函數調用進行模擬。 避免Java中的運算符重載使得Java的實現和規范變得更加簡單,並且它迫使程序員不要濫用運算符。 Java社區中有一些關於引入運算符重載的爭論。

Scala中運算符重載的優點和缺點與C ++中的相同 - 如果適當地使用運算符重載,則可以編寫更自然的代碼 - 如果不這樣,可以使用更加神秘,混淆的代碼。

僅供參考:操作符未被定義為C ++中的特殊函數,它們的行為與任何其他函數一樣 - 盡管名稱查找存在一些差異,它們是否需要是成員函數,以及它們可以通過兩種方式調用:1 )運算符語法,以及2)operator-function-id語法。

本文 - “ C ++和Java的積極遺產 ” - 直接回答您的問題。

“C ++既有堆棧分配又有堆分配,你必須重載你的操作符來處理所有情況而不會導致內存泄漏。確實很困難。但是,Java有一個存儲分配機制和一個垃圾收集器,這使得運營商重載變得微不足道”。 ..

Java錯誤地(根據作者)省略了運算符重載,因為它在C ++中很復雜,但是忘了為什么(或者沒有意識到它不適用於Java)。

值得慶幸的是,像Scala這樣的高級語言為開發人員提供了選項,同時仍然在同一個JVM上運行。

運算符重載沒有錯。 事實上,有一些錯誤與具有運算符重載數字類型。 (看一下使用BigInteger和BigDecimal的一些Java代碼。)

但是,C ++具有濫用該功能的傳統。 一個經常被引用的例子是比特移位運算符過載以進行I / O.

一般來說,這不是一件壞事。
C#等新語言也有運算符重載。

濫用運算符重載是一件壞事。

但是C ++中定義的運算符重載也存在問題。 因為重載運算符只是方法調用的語法糖,所以它們的行為就像方法一樣。 另一方面,普通的內置運算符的行為與方法不同。 這些不一致可能會導致問題。

我的頭頂操作員|| &&
這些內置版本是快捷操作符。 對於重載版本而言,情況並非如此,並且已導致一些問題。

事實上+ - * / all返回他們操作的相同類型(在運營商推廣之后)
重載版本可以返回任何內容(這是濫用設置的位置,如果您的操作員開始返回一些仲裁器類型,則用戶不期望事情會下降)。

操作符重載不是你真正“經常”需要的東西,但是當你使用Java時,如果你真的需要它,它會讓你想要撕掉你的指甲,這樣你就有借口停止打字。

你剛剛發現的代碼溢出了很長時間? 是的,你將不得不重新輸入整個批次以使其適用於BigInteger。 沒有什么比僅僅為了改變變量的類型而重新發明輪子更令人沮喪的了。

Guy Steele認為運營商超載也應該是Java,在他的主題演講“發展一種語言” - 有一個視頻和它的轉錄,這真是一個驚人的演講。 你會想知道他在前幾頁會談到什么,但如果你繼續閱讀,你會看到重點並獲得啟示。 事實上他可以做這樣的演講也很神奇。

與此同時,這次演講激發了許多基礎研究,可能包括Scala--這是每個人都應該閱讀以在該領域工作的論文之一。

回到這一點,他的例子主要是關於數字類(比如BigInteger,以及一些更奇怪的東西),但這並不重要。

但是,錯誤地使用運算符重載可能會導致可怕的結果,如果您嘗試讀取代碼而不仔細研究它使用的庫,那么即使正確使用也會使問題復雜化。 但這是個好主意嗎? OTOH,這些圖書館是否應該嘗試為其運營商提供操作員備忘單?

我相信每個答案都錯過了這個。 在C ++中,您可以根據需要重載運算符,但不能影響它們的優先級。 斯卡拉沒有這個問題,IIRC。

至於它是一個壞主意,除了優先級問題之外,人們對運營商提出了非常愚蠢的意義,它很少有助於提高可讀性。 Scala庫對於這個愚蠢的符號特別不好,你每次都必須記住這些符號,圖書館維護人員堅持不懈地說:“你只需要學習一次”。 好極了,現在我需要學習一些“聰明”作者的神秘語法*我關心的庫的數量。 如果存在總是提供有文化版本的運算符的慣例,那就不會那么糟糕了。

運算符重載不是C ++的發明 - 它來自Algol IIRC,甚至Gosling也沒有聲稱這是一個壞主意。

C ++中唯一已知錯誤的是缺乏將[] =作為單獨的運算符重載的能力。 這可能很難在C ++編譯器中實現,這可能不是一個明顯的原因,但很有價值。

正如其他答案所指出的那樣; 運算符重載本身並不一定是壞事。 當它以使得結果代碼不明顯的方式使用時會有什么不好。 一般來說,當你使用它們時,你需要讓它們做最不令人驚訝的事情(有操作符+做分區會給理性類的使用帶來麻煩)或者Scott Meyers說:

客戶已經知道像int這樣的類型的行為,因此你應該努力讓你的類型在合理的情況下以相同的方式運行...... 如果有疑問,請按照整數進行操作 (來自Effective C ++ 3rd Edition第18項)

現在有些人已經通過boost :: spirit等方式將運算符重載到極致。 在這個級別你不知道它是如何實現的,但是它會產生一個有趣的語法來獲得你想要的東西。 我不確定這是好還是壞。 看起來不錯,但我還沒用過它。

我從未見過一篇聲稱C ++的運算符重載很糟糕的文章。

用戶可定義的運算符允許該語言的用戶更容易更高水平的表達性和可用性。

但是,它似乎與C ++中的運算符重載沒有本質上的區別,因為我記得運算符被定義為特殊函數。

AFAIK,與“普通”成員函數相比,運算符函數沒有什么特別之處。 當然,您只有一組可以重載的運算符,但這並不會使它們變得非常特殊。

暫無
暫無

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

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