C ++はDよりも優れているのでしょうか?


135

私は最近Dを学んでおり、言語にある程度精通し始めています。私はそれが提供するものを知っています、私はまだすべてを使う方法を知りません、そして、Dイディオムなどについて多くを知りません、しかし、私は学んでいます。

私はDが好きです。これは素晴らしい言語であり、ある意味ではCの大規模な更新であり、うまく機能しています。どの機能も「ボルトオン」されているようには見えませんが、実際には非常によく考え抜かれ、適切に設計されています。

DはC ++であるべきだとよく耳にします(不必要な火炎戦争を避けるために、誰もが自分で決定するのが正しいかどうかは疑問です)。また、いくつかのC ++プログラマーから、C ++よりもはるかにDを楽しんでいると聞きました。

私自身はCを知っていますが、C ++を知っているとは言えません。C ++が言語として Dよりも優れている何かがあると思う場合、C ++とDの両方を知っている人から聞きたいです(通常の「サードパーティライブラリが多い」または「リソースが多い」または「 DよりもC ++を必要とするジョブが多い」)。

Dは、C ++が抱えていた多くの問題を修正するために、非常に熟練したC ++プログラマー(Walter BrightAndrei Alexandrescu、Dコミュニティの助けを借りて)によって設計されましたが、実際には結局良くならない何かがありましたか?彼が逃した何か?あなたがより良い解決策ではなかったと思うものはありますか?

また、私はD 1.0ではなくD 2.0について話していることに注意してください。


15
この辺りにD開発者よりもはるかに多くのC ++開発者がいると確信しているので、Dコミュニティがこれを見るようにしました。そうすれば、あなたはより興味深い、または少なくともさまざまな答えを得るでしょう。
クライム

7
また、D2はWalter Brightによって設計されましたが、Alexandrescuも使用しました。あなたはあなたの質問でそれを修正したいかもしれません。
クライム

2
@Klaim:Dと標準ライブラリにも多くのコミュニティの関与がありました(今でもそうです)。
ミカルミニッチ

28
@Anto言語としてのC ++は、プログラマーであるあなたをあなたの人生を憎むようにする点で、Dよりはるかに優れています。
アーレン

6
@jokoon:実際には、はい、非常に少ない作業で:digitalmars.com/d/2.0/interfaceToC.html
ANTO

回答:


124

C ++がDより優れていることのほとんどはメタのものです。C++には、より優れたコンパイラー、より優れたツール、より成熟したライブラリ、より多くのバインディング、より多くの専門家、より多くのチュートリアルなどがあります。より成熟した言語に期待します。これは議論の余地がありません。

言語自体に関しては、私の意見では、C ++がDよりも優れている点がいくつかあります。おそらくもっとありますが、ここに私の頭の一番上にリストできるものがいくつかあります:

C ++には、より優れた型システム
があります。現時点では、Dの型システムにはかなりの数の問題があり、設計上の見落としがあるようです。たとえば、構造体にクラスオブジェクト参照またはポインターが含まれている場合、constの推移性および値型に対するpostblitコンストラクターの動作により、const構造体を非const構造体にコピーすることは現在不可能です。アンドレイは、これを解決する方法を知っていると言いますが、詳細は述べませんでした。この問題は確かに修正可能です(C ++スタイルのコピーコンストラクターの導入は1つの修正になります)が、現在の言語では大きな問題です。

私を悩ませた別の問題は、論理定数の欠如です(つまりmutable、C ++にはない)。これは、スレッドセーフコードを記述するのに最適ですが、constオブジェクト内で遅延初期化を行うのは困難です(不可能ですか?)(最初の呼び出しで戻り値を構築してキャッシュするconst 'get'関数を考えてください)。

最後に、これらの既存の問題を考えると、私はどのように(型システムの残りの心配pureshared彼らが使用するように置かれた後などは、)の言語で他のすべてと相互に作用します。現在、標準ライブラリ(Phobos)は、Dの高度な型システムをほとんど使用していません。そのため、ストレスがかかっても耐えられるかどうかは問題だと思います。私は懐疑的ですが、楽観的です。

C ++にはいくつかのタイプシステムイボ(たとえば、非推移的なconst、iteratorなどconst_iterator)があり、非常にいことに注意してください。ただし、C ++ のタイプシステムは部分的には少し間違っていますが、D時々する。

編集:明確にするために、C ++の方がより良い考えの型システムを持っていると信じています。基本的に、DIでは、C ++には存在しない型システムのすべての側面を使用することに伴うリスクがあると感じています。

Dは時々少し便利すぎる
C ++についてよく耳にする批判の1つは、低レベルの問題を隠してしまうことです。たとえばa = b;、変換演算子の呼び出し、オーバーロード割り当て演算子の呼び出しなど、単純な割り当てが可能です。コードから見るのは難しい。このような人もいれば、そうでない人もいます。いずれにせよ、Dにそれが原因のようなものへの(よりよい?)悪化しているopDispatch@propertyopApplylazyあなたが期待していないものに無実探して、コードを変更する可能性を秘めています。

これは個人的には大きな問題ではないと思いますが、一部の人はこれを不快に思うかもしれません。

Dにはガベージコレクションが必要
です。GCなしでDを実行することは可能であるため、これは議論の余地があると考えられます。しかし、それが可能だからといって、それが実用的であるとは限りません。GCがなければ、Dの多くの機能が失われ、標準ライブラリを使用することは地雷原を歩くようなものになります(誰がメモリを割り当てるかを知っていますか?)。個人的には、GCなしでDを使用することは完全に非現実的であり、GCのファンでない場合(私のように)、これは非常に不快な場合があります。

Dの単純な配列定義はメモリを割り当てます
これは私の大嫌いです:

int[3] a = [1, 2, 3]; // in D, this allocates then copies
int a[3] = {1, 2, 3}; // in C++, this doesn't allocate

どうやら、Dでの割り当てを回避するには、次のことを行う必要があります。

static const int[3] staticA = [1, 2, 3]; // in data segment
int[3] a = staticA; // non-allocating copy

これらの小さな「背後」の割り当ては、これまでの2つのポイントの良い例です。

編集:これは既知の問題であり、現在作業中です。
編集:これは修正されました。割り当ては行われません。

結論
私はD vs C ++のマイナス面に焦点を当てましたが、それは質問が尋ねたものだからです。しかし、この投稿をC ++がDより優れているというステートメントとして見ないでください。 C ++より。どちらを使用するかを決定するのはあなた次第です。


私は数年前(2.0以前)にDを見ました。ガベージコレクションは実際には必要ありませんでした-デフォルトではそこにありましたが、低レベルのコードをオプトアウトできました。これについて間違っていると思ったのは、オプトインする方法を見つけることができないということです。たとえば、ツリーベースのコンテナでは、ライブラリコードがツリーノード自体のメモリを管理できます。ツリー全体は依然として収集可能であり、IIRCはこれらすべてのノードを収集するデストラクタです。ただし、そのコンテナ内のデータによって参照されるオブジェクトも収集可能である必要があります。GCのツリー内のすべてのデータ項目をマークするフックが必要です。
Steve314

3
低レベルのコードのGCを無効にすることもできます。ピーターは、言語は現在、GCに大きく依存していると言っています。また、core.memoryのAPI。GC.addRangeを使用して、マネージヒープ外の範囲をスキャンするようにGCに指示できます。
ウラジミールパンテレエフ

D標準ライブラリがガベージコレクションされており、GCオフコードがシームレスな相互運用性ではないことを指摘したため、+ 1。それは私がそれについて考えたものではありませんが、それは克服するべき大きなハードルのように見えます。
masonk

132

D開発に参加したとき、私はC ++について知っていることを最も知っている人の一人であるという独特の立場にいました。今、私はDについて最もよく知っている人の1人でもあるという、より独特な立場にいます。不思議なことに、私はこれを適切な信用や自慢する権利に言っているのではありませんこの質問に答える有利な立場。同じことがウォルターにも当てはまります。

概して、C ++(つまり、C ++ 2011の意味)がDよりも優れているかどうかを問うことは、「家を掃除するために専門家を雇うなら、彼らが去る場所はどこか」という質問と同じように矛盾しています。以前よりも汚れていますか?」C ++がDにはできなかった価値が何であれ、それは常に私とWalterにとって痛手だったので、ほとんどの定義から、C ++にはDの手の届かないところにないことはほとんどありません。

言語設計でほとんど理解されていないことの1つは(実際にいくつかの作業を行う運が少ないため)、見かけよりも強制されていないエラーがはるかに少ないことです。私たちの言語ユーザーの多くは、何らかの構造を見て、「うわー、これはとても間違っています!彼らは何を考えていましたか?」と言います。問題の事実は、言語のほとんどの厄介なインスタンスは、すべて健全で望ましいが、基本的に互いに競合または矛盾しているいくつかの基本的な決定の余波であるということです(たとえば、モジュール性と効率性、簡潔さと制御など)。

これらすべてを念頭に置いて、考えられるいくつかのことを列挙し、それぞれについて、Dの選択が他のより高いレベルの憲章を実現したいという欲求からどのように派生するかを説明します。

  1. Dは、すべてのオブジェクトがビット単位のコピーによって移動可能であると想定しています。これにより、少数のデザイン、特に内部ポインターを使用するデザイン、つまり内部にポインターを含むクラスがC ++に残ります。(このような設計はすべて、またはごくわずかな効率コストでDに変換できますが、翻訳作業が必要になります。)言語を大幅に簡素化し、ユーザーの介入なしまたは最小限でオブジェクトのコピーをより効率的にし、回避するためにこの決定を行いましたコピー構築の全体の泥沼と右辺値の参照機能がすべて備わっています。

  2. Dは、あいまいな性別タイプを許可しません(値タイプまたは参照タイプかどうかを判断できません)。そのような設計はC ++では満場一致で回避され、ほとんど常に間違っていますが、技術的には正しいものもあります。この選択を行ったのは、ほとんどが不正なコードを許可せず、再設計できるのはごく一部の正しいコードのみであるためです。それは良いトレードオフだと信じています。

  3. Dはマルチルート階層を許可しません。ここでの以前のポスターはこの特定のトピックについて非常に興奮しましたが、これはよく踏まれた根拠であり、共通のルートを持つ階層に対するルートレス階層の明白な利点はありません。

  4. Dでは、たとえばintをスローできません。Throwableを継承するオブジェクトをスローする必要があります。状況はDの方が優れているという争いはありませんが、DができないことはC ++ができることの1つです。

  5. C ++では、カプセル化の単位はクラスです。Dでは、モジュール(つまりファイル)です。Walterは、カプセル化をファイルシステム保護セマンティクスに自然にマッピングすることと、「友人」の必要性をなくすことの2つの理由でこの決定を行いました。この選択は、Dの全体的なモジュール設計に非常にうまく統合されています。C ++のように物事を変更することは可能ですが、それは物事を強制します。C ++のカプセル化スコープの選択は、C ++の物理設計にのみ適しています。

1つまたは2つの小さなものがありますが、全体的にはこれであるはずです。


6
@DeadMG:C ++で機能させるには、移動するオブジェクトに、それを指すオブジェクトへのバックポインターが必要です(コピー構築中に更新できるようにするため)。その場合は、Dでpostblitコンストラクターを使用して、とにかくポインターを更新できます。Dについて十分な知識がある場合は、Dに反論しないでください。
ピーターアレクサンダー

13
@Peter:ライフタイムは厳密にスコープベースですが、リファレンスにする必要がありますか?エイリアスを割り当てたいので、動的に割り当てるオーバーヘッドと、インダイレクションとキャッシュおよびコレクションのオーバーヘッドを無駄にする必要がありますか?また、同等のセマンティクスのために、コレクターが確定的に収集できることを願っています。それは明らかに、制御されていないことです。
DeadMG

3
@sbi:トップクラスの存在はあなたの選択にまったく影響しません。クラスタイプラティスでは、常に上部と下部があります。下部は、いくつかの言語でのみ明示的です。上部(オブジェクトなど)は、より多くの言語で明示的です。これらのタイプは常にコンセプトに存在します。それらもアクセス可能な場合、問題なく言語のユーザーにいくつかの追加機能を提供します。
アンドレイアレクサンドレスク

6
@quant_dev:BLASを使用した高性能線形代数に焦点を合わせたGSoCプロジェクトがすでに良好な状態にあると聞いてうれしいでしょう。また、テストおよびベンチマークの目的で適切なプリミティブの「単純な」実装を提供します。2番目の質問に答えるために、Javaは数値ライブラリを比較するための基準を非常に低く設定しています。高性能の代数ライブラリにアクセスするためのJNIの壁を越えるという問題が常に発生します。Javaには演算子のオーバーロードがないため、構文が悪くなります。
アンドレイアレクサンドレスク

4
@PeterAlexander:DeadMGはまさにその通りです。「値型へのポインタを使用すべきではありません」は、どの言語のポインタも一般に値型で使用されるという事実を明確に無視します(実際にObject*広く使用されているのを見int*ますか?)とDは完全に無視するようですパフォーマンスのペナルティ、または存在しないという主張。これは明らかに間違っています。キャッシュミスは多くの場合非常に顕著であるため、C ++は常にDよりも柔軟性に優れています。
Mehrdad

65

客観的にはDで多くを見つけるのは非常に難しいと思うC ++よりも悪い。あなたが客観的に悪いと言うことができるDの問題のほとんどは、実装品質の問題(一般的には言語と実装がどれだけ若いか、そして遅い速度で修正されているためです)、または問題ですサードパーティのライブラリが不足しています(これは時間とともに来ます)。言語自体は一般にC ++よりも優れており、言語としてのC ++の方が一般的なのは、C ++が一方に行き、Dが別の場所に行くというトレードオフがある場合、または誰かがその理由について主観的な理由がある場合あるものが他のものより優れていると思います。しかし、言語としてのC ++が優れている明確な客観的理由の数は、ほとんどありません。

実際、言語としてのC ++がDよりも優れている理由を考え出すには、本当に頭を悩ます必要があります。一般的に思い浮かぶのは、トレードオフの問題です。

  1. Dのconstは推移的であり、言語には不変あるため、C ++よりもはるかに強力な保証があります。constつまり、Dはを持たず、持たないことができますmutable論理constを持つことはできません。したがって、Dのconstシステムを使用すると大きな利点が得られますが、状況constによっては、C ++のように使用できない場合があります。

  2. Dには1つのキャスト演算子しかありませんが、C ++には4(Cキャスト演算子をカウントする場合は5)があります。これにより、一般的なケースではDでのキャストの処理が容易になりますが、実際に、const_castおよびその兄弟が提供する余分な複雑さ/利点が必要な場合は問題があります。しかし、実際にはDはテンプレートを使用してC ++のキャストを実装できるほど強力であるため、本当に必要な場合はテンプレートを使用できます(また、ある時点でDの標準ライブラリになることもあります)。

  3. DはC ++よりも暗黙のキャストがはるかに少なく、2つの関数が互いに競合していることを宣言する可能性がはるかに高い)。時々、それは迷惑な場合がありますが、あらゆる種類の機能ハイジャックの問題を防ぎます。あなたは本当にあなたが意味する関数を呼び出していることを知っています。

  4. D'sのモジュールシステムは、(、言及しないようにC ++のの#includeよりもはるかにきれいである方法より速くコンパイル時に)、それは、モジュールそのものを超えて名前空間を任意の種類を欠いています。したがって、モジュール内に名前空間が必要な場合は、Javaルートに移動して、クラスまたは構造体で静的関数を使用する必要があります。それは動作しますが、名前空間を本当に必要とする場合、明らかに実際の名前空間ほどきれいではありません。ただし、ほとんどの場合、モジュール自体が提供する名前空間は豊富です(実際に競合のようなものになると非常に洗練されます)。

  5. JavaとC#のように、Dは多重継承ではなく単一の継承を持ちますが、JavaとC#とは異なり、C ++の多重継承が持つすべての問題なしに同じ効果を得るための素晴らしい方法を提供します(そしてC ++の多重継承は非常に乱雑になります時には)。Dにはインターフェースがあるだけでなく、文字列ミックスインテンプレートミックスインエイリアスthisがあります。したがって、最終的な結果はほぼ間違いなく強力であり、C ++の多重継承が抱える問題のすべてを抱えているわけではありません。

  6. C#と同様に、Dは構造体クラスを分離します。クラスは継承を持ちObject、から派生した参照型であり、構造体は継承のない値型です。この分離は、良いことも悪いこともあります。C ++の古典的なスライシングの問題を取り除き、実際に値型である型をポリモーフィックであると想定される型から分離するのに役立ちますが、最初は、少なくともその区別はC ++プログラマにとって厄介かもしれません。最終的に、それには多くの利点がありますが、タイプを多少異なる方法で処理する必要があります。

  7. クラスのメンバー関数は、デフォルトでは多態的です。それらを非仮想として宣言することはできません。それらが可能かどうかを判断するのはコンパイラ次第です(最終クラスであり、基本クラスの関数をオーバーライドしていない場合にのみ当てはまります)。そのため、場合によってはパフォーマンスの問題になる可能性があります。ただし、ポリモーフィズムが本当に必要ない場合は、構造体を使用するだけで問題ありません。

  8. Dには組み込みのガベージコレクタがあります。C ++の多くは深刻な欠点であると考えており、現時点では、その実装には深刻な作業が必要になる可能性があります。改善されていますが、Javaのガベージコレクターとはまだ完全に一致していません。ただし、これは2つの要因によって軽減されます。1つは、スタックで主に構造体やその他のデータ型を使用している場合、それは大きな問題ではありません。プログラムがヒープ上のものを絶えず割り当てたり割り当て解除したりしていなければ、問題ありません。そして二人は、あなたはスキップすることができますガベージコレクタをあなたがしたい場合は、ちょうどCのを使用mallocしてfree。いくつかの言語機能があります(配列スライスなど))これを回避するか注意する必要があり、標準ライブラリの一部は少なくともGCの使用(特に文字列処理)なしでは実際には使用できませんが、次の場合はガベージコレクタを使用せずにDに書き込むことができますあなたは本当にしたい。賢明なことは、おそらく一般的にそれを使用してから、プロファイリングがパフォーマンスが重要なコードの問題を引き起こしていることを示す場合は避けることですが、必要であれば完全に回避できます。また、GCの実装の品質は時間の経過とともに向上し、GCの使用が引き起こす可能性のある多くの懸念が解消されます。したがって、最終的には、GCはそれほど大きな問題にはならず、Javaとは異なり、必要に応じてGCを回避できます。

おそらく他にもありますが、それは私が現時点で思い付くことができるものです。そして、あなたが気づくならば、それらはすべてトレードオフです。Dは、C ++がそれらを行う方法よりも明確な利点を持っているが、いくつかの欠点も持っている、C ++とは異なることを行うことを選択しました。どちらが良いかはあなたが何をしているかに依存し、多くの場合、最初はおそらく悪く見えるだけで、慣れれば問題はありません。どちらかといえば、Dの問題は一般に、他の言語がこれまで行ったことのない、またはDのようにまったく行っていない新しいことによって引き起こされる新しい問題になります。全体として、DはC ++の間違いから非常によく学んでいます。

そして、言語としてのDは、C ++よりも多くの点で改善されているので、一般的にDは客観的に優れていると思います。

  1. Dには条件付きコンパイルがあります。これは、C ++でプログラミングしているときによく見逃す機能の1つです。C ++が追加する場合、C ++はテンプレートのようなものになると飛躍的に向上します。

  2. Dにはコンパイル時リフレクションがあります。

  3. 変数はデフォルトでスレッドローカルですがshared、必要に応じて変更できます。これにより、スレッドの処理がC ++よりもはるかにクリーンになります。あなたは完全にコントロールできます。メッセージの受け渡しを使用immutableしてスレッド間で通信したり、変数を作成して、ミューテックスと条件変数を使用してC ++の方法で実行したりできます。さらに、同期化の導入によりC ++よりも改善されています(C#およびJavaと同様)。したがって、Dのスレッド化の状況はC ++の状況よりもはるかに優れています。shared

  4. DのテンプレートはC ++のテンプレートよりもはるかに強力であり、より多くの操作をはるかに簡単に実行できます。そして、テンプレートの制約を追加して、エラーメッセージがある方法で、彼らはC ++であるよりも優れています。Dは、テンプレートを非常に強力で使いやすくします。Modern C ++ Designの作成者がDの主要な協力者の1人であることは偶然ではありません。Dテンプレートと比較して、C ++テンプレートは非常に不足していることがわかりました。C++でプログラミングするときには、非常にイライラすることがあります。

  5. Dには組み込みのコントラクトプログラミングがあります。

  6. Dには、単体テストフレームワークが組み込まれています。

  7. Dは、string(UTF-8)、wstring(UTF-16)、およびdstring(UTF-32)を使用したUnicodeの組み込みサポートを備えています。これにより、ユニコードの処理が簡単になります。使用したいだけでstring、一般的にユニコードを気にしたくない場合は、できます。ただし、ユニコードの基本をある程度理解していれば、標準ライブラリ関数の一部に役立ちます。

  8. Dの演算子のオーバーロードはC ++のオーバーロードよりも優れており、1つの関数を使用して複数の演算子を同時にオーバーロードできます。これの主な例は、基本的な算術演算子をオーバーロードする必要があり、その実装が演算子を除いて同一である場合です。ストリングミックスインにより、簡単に1つのシンプルな関数定義を作成できます。

  9. Dの配列は、C ++の配列よりもはるかに優れています。長さのある適切なタイプであるだけでなく、追加やサイズ変更が可能です。それらを連結するのは簡単です。そして何よりも、スライスがあります。そして、それは効率的な配列処理にとって大きな恩恵です。文字列はDの文字の配列であり、Dの配列は非常に強力であるため、問題ではありません(実際には素晴らしいことです!)。

ずっと続けられました。Dが提供する改善の多くはささいなことではありません(thisコンストラクター名に使用したり、セミコロンがボディ全体であるifステートメントまたはループボディを許可しないなど)が、それらのいくつかは非常に大きく、すべてを追加すると、なり非常に優れたプログラミングの経験。C ++ 0xは、DがC ++に欠けていた機能(autoラムダなど)の一部を追加しますが、すべての改善があったとしても、Dよりも言語としてのC ++について客観的に優れているものはまだ多くありません。

他のものよりも好きになる主観的な理由がたくさんあることは間違いありません。Dの実装の相対的な未熟さが時々問題になることがあります(特にリポジトリがgithubに移動されて以来、非常に急速に改善されています) 、サードパーティのライブラリの欠如は間違いなく問題になります(ただし、DはC関数を簡単に呼び出すことができますが、C ++関数はそれほどではありませんが、問題を確実に軽減します)。ただし、これらは言語自体の問題ではなく、実装品質の問題です。実装品質の問題が修正されると、Dを使用するのがはるかに快適になります。

したがって、この質問に対する短い答えは「非常に少ない」と思います。言語としてのDは、一般にC ++よりも優れています。


2
ガベージコレクション言語は、GC以外の言語(YTに関するAlexandrescuの講演による)よりも2〜5倍多くのメモリを使用するため、それ(メモリ使用量)がボトルネックである場合は間違いなく問題になります。
-NoSenseEtAl

9

RAIIおよびスタックメモリ使用量

D 2.0はscope、スタック上でクラスインスタンスを割り当てる際にキーワードの値を削除したため、スタック上でRAIIが発生することを許可しません。

Dで値型の継承を行うことはできないため、RAIIの任意の形式に対してヒープの割り当てを効果的に行うことができます。
つまり、を使用しない限り、手作業でメモリを割り当てる必要があるため、使用するemplaceのは非常に苦痛です。(emplaceDで使用するのが実用的であるとはまだわかっていません。)


6

C ++を使用すると、冗長にする必要があります。これは、推論が好きか冗長性が好きかによって、あなたの目には良くも悪くもなります。

C ++でのランタイムメモ化を比較します

template <typename ReturnType, typename... Args>
function<ReturnType (Args...)> memoize(function<ReturnType (Args...)> func)
{
    map<tuple<Args...>, ReturnType> cache;
    return ([=](Args... args) mutable {
            tuple<Args...> t(args...);
            return cache.find(t) == cache.end()
                ? cache[t] : cache[t] = func(args...);
    });
}

Dの同じことで:

auto memoize(F)(F func)
{
    alias ParameterTypeTuple!F Args;
    ReturnType!F[Tuple!Args] cache;
    return (Args args)
    {
        auto key = tuple(args);
        return key in cache ? cache[key] : (cache[key] = func(args));
    };
}

たとえば、template <typename ReturnType, typename... Args>(F)Args...Argsargs...argsなどの余分な冗長性に注意してください。
良くも悪くも、C ++はより冗長です。

もちろん、Dでこれを行うこともできます。

template memoize(Return, Args...)
{
    Return delegate(Args) memoize(Return delegate(Args) func)
    {
        Return[Tuple!Args] cache;
        return delegate(Args args)
        {
            auto key = tuple(args);
            return key in cache ? cache[key] : (cache[key] = func(args));
        };
    }
}

そして、彼らはほとんど同じに見えるだろうが、これが必要になりdelegate、元の受け入れに対し、任意の呼び出し可能オブジェクトを。(C ++ 0xバージョンstd::functionオブジェクトを必要とするので、どちらの場合も、入力はより冗長で制限されています...これは、冗長性が好きな場合は良いかもしれませんし、そうでない場合は悪いかもしれません。)


2

私はDについてあまり知りませんが、私が知っている多くの多くのC ++プログラマーはそれを非常に嫌っています。私は個人的に同意しなければなりません-私はDの外観が好きではなく、より近いものを取りません

Dがこれ以上の牽引力を得ていない理由を理解するためには、何が人々をC ++に引き付けるかを理解することから始める必要があります。つまり、一番の理由はコントロールです。C ++でプログラミングすると、プログラムを完全に制御できます。標準ライブラリを置き換えたいですか?あなたはできる。安全でないポインターキャストを行いたいですか?あなたはできる。const-correctnessに違反したいですか?あなたはできる。メモリアロケーターを交換したいですか?あなたはできる。タイプに関係なく生メモリをコピーしたいですか?本当にしたい場合。複数の実装から継承したいですか?それはあなたの葬式です。地獄、Boehmコレクターのようなガベージコレクションライブラリを取得することもできます。次に、パフォーマンスなどの問題があります。これは、制御に密接に追随します。プログラマーの制御が強いほど、プログラムをより最適化できます。

ちょっとした調査をして、それを試した数人の人に話しかけたときに私が見たことがいくつかあります。

統一されたタイプ階層。C ++ユーザーが継承を使用することはほとんどありません。ほとんどのC ++プログラマーは合成を好みます。タイプを継承するのは、そうする理由が十分にある場合にのみ継承を介してリンクする必要があります。オブジェクトの概念は、すべてのタイプをリンクすることにより、この原則に強く違反します。さらに、C ++の最も基本的な原則の1つに違反しているため、必要なものだけを使用します。Objectからの継承についての選択肢が与えられていないこと、およびそれに伴うコストは、プログラマーが自分のプログラムを制御できるという点で、C ++が言語として意味するものに非常に強く反対しています。

関数とデリゲートの問題について聞いたことがあります。どうやら、Dには実行時呼び出し可能関数型として関数デリゲートの両方があり、それらは同じではありませんが、交換可能です... 私の友人は彼らにいくつかの問題を抱えていました。これは間違いなくC ++からのダウングレードであり、これでstd::function完了です。

次に、互換性があります。DはC ++と特に互換性がありません。私が意味する、何の言語はC ++ / CLIを除いて、それに直面させ、C ++との互換性がありません不正行為の一種であるが、参入障壁として、言及されるように持っています。

それから、他にもいくつかあります。たとえば、Wikipediaのエントリを読むだけです。

import std.metastrings;
pragma(msg, Format!("7! = %s", fact_7));
pragma(msg, Format!("9! = %s", fact_9));

printfgets古いC標準ライブラリのような大きな問題と同じファミリで、これまでに考案された最も安全でない関数の1つです。Stack Overflowで検索すると、誤用に関する多くの質問が見つかります。基本的に、DRYのprintf違反です-書式文字列で型を指定し、引数を指定したときに再度指定します。DRYの違反で、間違えた場合、非常に悪いことが起こります。たとえば、typedefを16ビット整数から32ビット整数に変更した場合です。また、まったく拡張可能ではありません。誰もが独自の形式指定子を考案した場合にどうなるか想像してください。C ++のiostreamは遅く、演算子の選択は最大でなく、インターフェースは作業を使用できますが、基本的に安全であることが保証されており、DRYは違反されず、容易に拡張できます。これは言えることではありませんprintf

多重継承はありません。それ、C ++のやり方ではありません。C ++プログラマは、プログラムを完全に制御できることを期待しており、継承できないものを強制する言語はその原則に違反しています。さらに、デフォルトの実装などを提供するためにインターフェイスからクラスに型を変更すると、突然すべてのユーザーのコードが破損するため、継承(さらに)が脆弱になります。それは良いことではありません。

別の例はあるstringwstring。C ++では、それらの間で変換する必要があり、すでにこのライブラリはUnicodeをサポートしており、この古いCライブラリはのみを使用しconst char*、必要な文字列引数タイプに応じて同じ関数の異なるバージョンを記述する必要があります。たとえば、Windowsヘッダーには、たとえば、独自のコードを妨害することが多い問題に対処するための非常に刺激的なマクロがいくつかあります。dstringミックスに追加しても事態が悪化するだけです。2つの文字列タイプではなく、3つを管理する必要があります。複数の文字列型を使用すると、メンテナンスの負担が増え、文字列を処理する反復コードが導入されます。

スコット・マイヤーズはこう書いている:

Dは、プログラマーが最新のソフトウェア開発の課題に取り組むのを支援するために構築されたプログラミング言語です。これは、正確なインターフェース、緊密に統合されたプログラミングパラダイムの連携、言語によるスレッド分離、モジュール型の安全性、効率的なメモリモデルなどを通じて相互接続されたモジュールを育成することで実現します。

言語によるスレッド分離はプラスではありません。C ++プログラマーは、プログラムを完全に制御できることを期待しており、何かを強制する言語は、医師が注文したものではないことは間違いありません。

また、コンパイル時の文字列操作についても説明します。Dには、コンパイル時にDコードを解釈する機能があります。これはプラスではありません。すべてのベテランC ++プログラマーによく知られているCの比較的限られたプリプロセッサーによって引き起こされる大きな頭痛を考慮して、この機能がどれほどひどく悪用されるか想像してください。コンパイル時にDコードを作成する機能は優れていますが、構文ではなくセマンティックでなければなりません。

さらに、特定の反射が期待できます。Dにはガベージコレクションがあり、C ++プログラマは、哲学でJavaやC#のような言語にかなり直接的に反対する言語に関連付けます。また、構文の類似点もあります。これは必ずしも客観的に正当化できるわけではありませんが、注意すべき点です。

基本的に、C ++プログラマーがまだできないことはそれほど多くありません。Dで階乗メタプログラムを書く方が簡単かもしれませんが、すでにC ++で階乗メタプログラムを書くことができます。おそらくDでは、コンパイル時のレイトレーサーを作成できます、とにかくそれを実行したい人はいません。C ++哲学の根本的な違反と比較して、Dでできることは特に注目に値しません。

これらが表面上の問題にすぎない場合でも、表面上では、Dが実際にはC ++のように見えないという事実は、おそらく多くのC ++プログラマーがDに移行していない正当な理由であると確信しています。おそらく、Dは自分自身により良い仕事をする必要があります。


9
@DeadMG:それは100%間違いであり、言うべきありませこれは間違いなくC ++からのダウングレードであり、これでstd::function完了です。どうして?たとえば、あなたも関数ポインタを持っているからです。それはだまさに Dで同じこと:D's「の機能は、」関数ポインタであり、D's「の代表は、」C ++のと同じであるstd::function(彼らはビルトインしていることを除いて)。どこにも「ダウングレード」はありません。また、それらの間には1対1の対応があるため、C ++に精通していれば混乱することはありません。
Mehrdad

10
@Mark Trapp:トピックに対するあなたのスタンスを十分に理解していないことを認めなければなりません。コメントは答えにコメントするために使用されるべきではありませんか?
klickverbot

6
@Mark Trapp:私のポイントは、ここでのコメントのほとんどは時代遅れではなかったということです(リンクしたメタディスカッションは、元の投稿に既に組み込まれた提案に特に適用されます)が、まだ存在する投稿の事実上の不正確さを指摘しました。
klickverbot

7
フォーマットに関する注意:Dのフォーマット関数はタイプセーフであり(安全性/オーバーフローの問題を解決します)、フォーマット文字列は引数のタイプではなく、引数のフォーマット方法のみを指定するため、DRYに違反しません。これは、Dのタイプセーフな変数のおかげで可能です。したがって、少なくともその異議は完全に無効です。
ジャスティンW

17
@Mark:それらに関する現在のポリシーが何であれ、私はそれが愚かであり、コメントの議論が削除されるのを妨げるとわかります。この回答には広範な議論があったと思います(今は興味があります)が、確信が持てず、見つける方法がありません。あなたがリンクしたその部屋には10,000以上のメッセージがあり、私は起こったことを覚えていると思われる議論を見つける機会は全くありませんが、その内容を思い出すことができません。この回答に関する議論は、チャットルームではなく、この回答に属します。そこでは、セックス、ドラッグ、ロックンロールの議論に混じり合う可能性があります。
sbi

1

C ++で私が感謝していることの1つは、関数の引数または戻り値をポインターではなくC ++参照として文書化できることnullです。したがって、値を取得しないことを意味します。

Dバージョン:

class A { int i; }

int foo(A a) {
    return a.i; // Will crash if a is null
}

int main() {
    A bar = null;
    // Do something, forgetting to set bar in all
    // branches until finally ending up at:
    return foo(bar);
}

C ++バージョン:

class A { int i; };

int foo(A& a) {
    return a.i; // Will probably not crash since
                // C++ references are less likely
                // to be null.
}

int main() {
    A* bar = null;
    // Do something, forgetting to set bar in all
    // branches until finally ending up at:
    // Hm.. I have to dereference the bar-pointer
    // here, otherwise it wont compile.  Lets add
    // a check for null before.
    if (bar)
        return foo(*bar);
    return 0;
}

公平を期すためにA、D structにしてfoo()-argumentをマークすることで、C ++に非常に近づけることができますref(クラスは参照型であり、構造体はC#と同様にDの値型です)。

NonNullable代わりに、クラスのテンプレートをD標準ライブラリコンストラクトとして作成する計画があると思います。それでも、私はにType&比べての簡潔さNonNullable(Type)が好きで、デフォルトとしてnull不可を好みます(TypeandのようなものをレンダリングしますNullable(Type))。しかし、Dでそれを変更するのは遅すぎて、私は今話題から外れています。


3
Dの関数引数と戻り値の両方にマークを付けてref、C ++と同じ効果を得ることができます&。1つの大きな違いは、refたとえそれがであっても一時的でないことconstです。
ジョナサンMデイビス

ローカル変数への参照を返すことがDで禁止されている方法が気に入っています。あなたのコメントを読むまで、私はそれを知りませんでした。しかし、Cの逆参照演算子が考えさせるような方法で、考えなくても非ローカルのnull参照を返すことができます。
ルマー

あなたは物事を混乱させています。クラスは常に参照であり、参照とは別のものです。Dの参照は、Javaの参照に似ています。それらは管理されたポインターです。refによる受け渡しは、C ++での&による受け渡しに似ています。refでクラス参照を渡すことは、C ++でポインタを&で渡すことに似ています(例:A *&)。クラスはスタックに置かれません。はい、NonNullableは、nullでないことが保証されたクラス参照を持つことを可能にしますが、それはrefとは完全に別です。C ++コードでやろうとしていることは、クラスがスタックに置かれないため、Dでは機能しません。構造体はそうです。
ジョナサンMデイビス

1
そう、そう、nullabe以外のクラス参照を持つことができればいいのですが、C ++はクラスをスタック上に置いたり、ポインターを逆参照したりできるので、あなたが示していることをなんとかすることができます。また、Dでポインターを間接参照できます、クラスはポインターではなく参照であるため、間接参照することはできません。それらをスタックに置くことはできず、逆参照することもできないので、nullにできないクラスをDに組み込む方法はありません。それ損失ですが、NonNullableはそれを修正し、構造体とクラスの分離から得られる利益はとにかく一般的に大きくなります。
ジョナサンMデイビス

2
言語標準では、C ++参照をnullにすることはできません(nullにできないため、「おそらくnullにならない」と言うのは誤りです)。クラスの有効な値としてnullを許可しない方法があればいいのにと思います。
-jsternberg

1

C ++がDよりも「優れている」という最も重要なことは、レガシーライブラリとのインターフェイスです。さまざまな3Dエンジン、OpenCLなど。Dは新しいので、選択できるライブラリの数ははるかに少ないです。

C ++とDのもう1つの重要な違いは、C ++には複数の経済的に独立したベンダーがありますが、2014年の時点で、Dには実際にたった2人のチームしかいないということです。興味深いのは、プロジェクトがテクノロジに依存するべきではないという「第2のソース原則」、つまり、単一のベンダーしか持たないコンポーネントがソフトウェアに対しても当てはまるように見えることです。

比較のために、Rubyインタープリターの最初のバージョンは、Rubyの発明者である松本幸宏によって書かれましたが、2014年の主流のRubyインタープリターは、他の人によって事実上ゼロから書かれました。したがって、Rubyは複数の経済的に独立したベンダーを持つ言語と見なすことができます。一方、Dは素晴らしい技術ですが、それを開発する少数の開発者に依存します。

Javaの歴史は、テクノロジー(この場合はJava)に素晴らしい、しかし単一の投資家がいたとしても、巨大な企業ユーザーベースに関係なく、テクノロジーが本質的に廃棄されるという大きなリスクがあることを示しています。ECが「実行委員会」の略であるApache Software Foundationの引用:

オラクルはECにJava SE 7仕様の要求とライセンスを提供しましたが、これらは自己矛盾し、仕様の独立した実装の配布を厳しく制限し、最も重要なこととして、仕様の独立したオープンソース実装の配布を禁止します。

歴史的なメモとして、HTML5 WebGLが開発される何年も前に、Javaアプレットにはハードウェアアクセラレーションによる3Dキャンバスがあったと言えます。Javaがコミュニティプロジェクトであった場合、Javaアプレットの起動速度の問題は解決できたかもしれませんが、Javaの唯一の投資家であるSun Microsystemsの幹部は、Java実装を修正するのに十分な重要性を感じていませんでした。最終結果:Java GUIフレームワーク(Swingなど)の「貧乏人のレプリカ」としての複数のベンダーによるHTML5キャンバス。興味深いことに、サーバー側では、Pythonプログラミング言語にはJavaが約束したのと同じ利点があります。Pythonアプリケーションがマシンコードにコンパイルされていない場合、ハードウェアに関係なく、1回書くだけですべてのサーバーで実行できます。PythonはJavaとほぼ同じくらい古い/若いですが、Javaとは異なり、

概要:

生産用のテクノロジーを評価する場合、テクノロジーの最も重要な特性は、それを開発する人々、社会プロセス、開発が行われる場所、および財政的に独立した開発チームの数です。

テクノロジーT2よりもテクノロジーT1を使用する方が有利かどうかは、テクノロジーのベンダーによって異なり、テクノロジーT1がプロジェクト関連の問題をT2よりも安く解決できるかどうかによって異なります。たとえば、単一サプライヤの問題が無視された場合、Javaバイナリは新しいハードウェアへの展開時の再コンパイルやメモリ管理関連のソフトウェア開発作業の量を必要としないため、情報システムではJavaはC ++よりも「優れた」テクノロジーになりますJavaの方がC ++よりも小さいです。他のライブラリに依存しないプロジェクトなど、ゼロから開発されたプロジェクトは、C ++よりもDで開発する方が安価かもしれませんが、一方で、C ++には複数のベンダーがあるため、長期的にはリスクが低くなります。 。(Javaの例では、Sun Microsystemsはほとんど問題ありませんでしたが、

いくつかのC ++制限に対する可能な回避策

C ++の制限のいくつかに対する考えられる回避策の1つは、デザインパターンを使用することです。このデザインパターンでは、最初のタスクが断片に分割され、断片が「ソート」されます(分類、クラスター化、分割、同じもの)から2つのクラス:ロジック関連タスクを制御します。メモリアクセスパターンでは局所性を許可しません。信号処理のようなタスク。局所性が容易に達成されます。信号処理の「類似」タスクは、比較的単純なコンソールプログラムのセットとして実装できます。制御ロジック関連のタスクはすべて、RubyやPythonなどで記述された単一のスクリプトに配置され、ソフトウェア開発の快適性が速度よりも優先されます。

高価なオペレーティングシステムプロセスの初期化とオペレーティングシステムプロセス間のデータコピーを回避するために、小さなC ++コンソールアプリケーションのセットは、Ruby / Pythonなどによって「サーブレット」として起動される単一のC ++プログラムとして実装できます。脚本。Ruby / Python /など。スクリプトは、終了前にサーブレットをシャットダウンします。「サーブレット」とRuby / Python /などの間の通信。スクリプトは、Linuxの名前付きパイプまたは同様のメカニズムで実行されます。

最初のタスクが前述の2つのクラスに分類できる部分に簡単に分割できない場合は、最初のタスクが変更されるように問題を言い換える必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.