web-dev-qa-db-ja.com

Scalaの演算子が「良い」のにオーバーロードしているのに、C ++の「悪い」のはなぜですか?

C++での演算子のオーバーロードは、多くの人が悪いこと(tm)であると見なされており、新しい言語では繰り返されない間違いです。確かに、これはJavaの設計時に具体的に削除された機能の1つでした。

Scalaを読み始めた今、私はそれが演算子のオーバーロードに非常に似ているものを持っていることに気付きます(ただし、技術的には演算子がなく、関数のみがあるため、演算子のオーバーロードはありません)。しかし、私が思い出すように、演算子は特別な関数として定義されている、C++での演算子のオーバーロードと質的には異なるようには見えません。

だから私の質問は、「=」をScalaで定義するというアイデアを、C++でよりも良いアイデアにしているのはなぜですか?

153
skaffman

C++はCから真の青い演算子を継承します。つまり、6 + 4の「+」は非常に特別なものです。たとえば、その+関数へのポインタを取得することはできません。

一方、Scalaにはそのような演算子はありません。メソッド名を定義する柔軟性が非常に高く、Word以外のシンボルの組み込み優先順位が少しあります。したがって、技術的にScalaには演算子のオーバーロードはありません。

何を呼び出したいとしても、C++であっても演算子のオーバーロードは本質的に悪くありません。問題は、悪いプログラマーが悪用するときです。しかし、率直に言って、私は、プログラマーがオペレーターのオーバーロードを悪用する能力を奪うことは、プログラマーが悪用できるすべてのものを修正するというバケツを落とさないと考えています。本当の答えはメンタリングです。 http://james-iry.blogspot.com/2009/03/operator-overloading-ad-absurdum.html

それにもかかわらず、C++の演算子のオーバーロードとScalaの柔軟なメソッドの命名には違いがあり、IMHOはScala悪用性が低く、悪用性が高い。

C++では、修正表記法を取得する唯一の方法は演算子を使用することです。それ以外の場合は、object.message(argument)またはpointer-> messsage(argument)またはfunction(argument1、argument2)を使用する必要があります。したがって、コードに特定のDSL風のスタイルが必要な場合は、演算子を使用する必要があります。

In Scalaどのメッセージ送信でも挿入記法を取得できます。「オブジェクトメッセージ引数」は完全に大丈夫です。つまり、挿入記法を取得するために非Wordシンボルを使用する必要はありません。

C++演算子のオーバーロードは、本質的にC演算子に制限されています。 「+」や「>>」のような比較的少数の記号に広範囲の無関係な概念をマップしようとする人々に圧力をかける中置演算子を使用できるという制限と組み合わせて

Scalaでは、メソッド名として有効な非Wordシンボルを広範囲に使用できます。たとえば、私はあなたが書くことができる組み込みのPrologのような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のような、Word以外の関数とメソッド名を柔軟に使用できる他の言語については、Scalaのように、すべての「演算子」が単なる別のメソッドであり、プログラマーが柔軟に名前を付けた固定性と固定性を定義できるHaskellを参照してください関数。

238
James Iry

C++での演算子のオーバーロードは、多くの人がA Bad Thing(tm)と見なしています

無知によってのみ。 C++のような言語では絶対に必要であり、「純粋な」見方を始めた他の言語が、設計者が必要性を発見したときに追加したことは注目に値します。

65
anon

演算子のオーバーロードは、C++では決して一般的に悪い考えとは考えられていませんでした-演算子のオーバーロードの悪用だけが悪い考えと考えられていました。とにかくより冗長な関数呼び出しでシミュレートできるため、言語での演算子のオーバーロードは実際には必要ありません。 Javaでの演算子のオーバーロードを回避することにより、Javaの実装と仕様が少し単純になり、プログラマーが演算子を乱用しないように強制されました。 Java演算子のオーバーロードの導入に関するコミュニティ。

Scalaでの演算子のオーバーロードの長所と短所は、C++と同じです。適切に演算子のオーバーロードを使用すると、より自然なコードを記述できます。

参考:演算子はC++で特別な関数として定義されておらず、他の関数と同じように動作します-名前のルックアップ、メンバー関数である必要があるかどうか、2つの方法で呼び出すことができるという違いがあります:1 )演算子構文、および2)operator-function-id構文。

41
Faisal Vali

この記事-" C++およびJavaのポジティブレガシー "-質問に直接回答します。

「C++にはスタック割り当てとヒープ割り当ての両方があり、すべての状況を処理し、メモリリークを引き起こさないように演算子をオーバーロードする必要があります。実際、Javaには単一のストレージ割り当てメカニズムとガベージコレクタがあり、演算子のオーバーロードを簡単にします」 ..

JavaはC++では複雑であるため、誤って(著者によると)演算子のオーバーロードを省略しましたが、理由を忘れました(または、Javaに適用されないことに気づきませんでした)。

ありがたいことに、Scalaなどの高レベル言語は、同じJVM上で実行中に開発者にオプションを提供します。

18
jmanning2k

演算子のオーバーロードに問題はありません。実際、notに数値型の演算子のオーバーロードがあると何か問題があります。 (いくつかのJavaコードを見てください。)

ただし、C++にはこの機能を悪用する伝統があります。よく引用される例は、ビットシフト演算子がI/Oを実行するためにオーバーロードされることです。

9
dan04

一般的に、それは悪いことではありません。
C#などの新しい言語にも演算子のオーバーロードがあります。

悪いのは、オペレーターのオーバーロードの濫用です。

ただし、C++で定義されている演算子のオーバーロードにも問題があります。オーバーロードされた演算子は、メソッド呼び出しの単なる構文糖であるため、メソッドのように動作します。一方、通常の組み込み演算子はメソッドのようには動作しません。これらの不整合は問題の原因になる可能性があります。

私の頭の上のオペレーター||および&&
これらの組み込みバージョンは、ショートカット演算子です。これは、オーバーロードされたバージョンには当てはまらず、いくつかの問題を引き起こしています。

+-* /すべてが操作対象と同じ型を返すという事実(オペレーター昇格後)
オーバーロードされたバージョンは、何でも返すことができます(これは、乱用が始まる場所です。オペレーターが何らかの調停者タイプを返し始めた場合、ユーザーは物事がうまくいかないと予想していました)。

8
Martin York

演算子のオーバーロードは頻繁に「必要」なものではありませんが、Javaを使用しているときに本当に必要な箇所に到達した場合、入力を止める言い訳をするために爪を引き裂こうとするでしょう。 。

あなたが今見つけたコードは長いオーバーフローですか?うん、BigIntegerで動作するようにロット全体を再入力する必要があります。変数の型を変更するためだけに車輪を再発明しなければならないことに、それ以上イライラすることはありません。

7
Steve Thomas

Guy Steeleは、演算子のオーバーロードはJavaのキーノートスピーチ「言語の成長」でも行われるべきだと主張しました。最初の数ページで彼が何について話しているのか疑問に思うかもしれませんが、読み続けると、ポイントがわかり、啓発を達成することができます。

同時に、この講演は、おそらくScala-を含む多くの基礎研究を刺激しました。

ポイントに戻ると、彼の例は主に数値クラス(BigIntegerなど)についてのものですが、それは必須ではありません。

ただし、演​​算子のオーバーロードの誤用はひどい結果につながる可能性があり、使用するライブラリを少しも調べずにコードを読み取ろうとすると、適切な使用でも問題が複雑になる可能性があります。しかし、それは良いアイデアですか? OTOH、そのようなライブラリは、オペレータのオペレータのチートシートを含めるようにすべきではありませんか?

6
Blaisorblade

私はすべての答えがこれを逃したと信じています。 C++では、必要なすべての演算子をオーバーロードできますが、評価される優先順位に影響を与えることはできません。 Scalaにはこの問題はありません、IIRC。

悪い考えについては、優先順位の問題に加えて、人々はオペレータにとって非常に意味のない意味を思いつき、読みやすさをめったに助けません。 Scalaライブラリは特に悪いです。毎回暗記する必要のある間抜けなシンボルで、ライブラリのメンテナが砂に頭を突き刺して「一度学ぶだけでいい」と言っています。 「賢い」著者の暗号構文*使用したいライブラリの数を学習する必要がありますが、常に文芸バージョンの演算子を提供する慣習が存在していれば、それほど悪くはないでしょう。

4
Saem

C++で間違っていることがわかっている唯一のことは、[] =を個別の演算子としてオーバーロードする機能がないことです。これはおそらく明白な理由ではないが、それだけの価値があるため、C++コンパイラに実装するのは難しいかもしれません。

3
Joshua

演算子のオーバーロードはC++の発明ではありませんでした-それはALGOL IIRCに由来し、ゴスリングでさえ一般的に悪い考えだと主張していません。

3

C++の演算子のオーバーロードが悪いと主張する記事を見たことはありません。

ユーザー定義可能な演算子を使用すると、言語のユーザーがより簡単に、より高いレベルの表現力と使いやすさを実現できます。

2
Paul Nathan

しかし、私が思い出すように、演算子は特別な関数として定義されている、C++での演算子のオーバーロードと質的には異なるようには見えません。

知る限り、演算子関数には「通常の」メンバー関数と比較して特別なものはありません。もちろん、オーバーロードできる特定の演算子のセットしかありませんが、それはそれらを特別なものにするものではありません。

1
John Smith