私は最近 [〜#〜] d [〜#〜] を学び、言語にある程度の親しみを持ち始めています。私はそれが何を提供しているかを知っています、私はまだすべての使い方を知りません、そしてDイディオムなどについてはあまり知りませんが、私は学んでいます。
私はDが好きです。これは、ある意味でCの(== --- ==)huge更新であるナイス言語であり、適切に行われます。どの機能も「ボルトオン」されているようには見えませんが、実際にはかなりよく考え抜かれており、うまく設計されています。
DはC++のあるべき姿であるとよく耳にするでしょう(私はそれが正しいかどうかを質問します不必要な炎の戦争を避けるために)。また、いくつかのC++プログラマーから、C++よりもDを楽しんでいると聞いています。
私自身、Cを知っていますが、C++を知っているとは言えません。言語としてC++がDよりも優れている(通常ではない)と思う人がいる場合、C++とDの両方を知っている人から連絡をもらいたい「サードパーティライブラリが多い」、「リソースが多い」、「DよりもC++を必要とするジョブが多い」など)。
Dは、非常に熟練したC++プログラマー( Walter Bright および Andrei Alexandresc がDコミュニティの助けを借りて)によって設計され、C++が抱えていた多くの問題を修正しましたが、結局改善されなかったものはありますか?彼が逃した何か?あなたがより良い解決策ではなかったと思う何か?
C++がDよりも「優れている」ことのほとんどはメタなものです。C++には、より優れたコンパイラー、より優れたツール、より成熟したライブラリ、より多くのバインディング、より多くの専門家、より多くのチュートリアルなどがあります。より成熟した言語から期待します。これは議論の余地がない。
言語自体については、私の意見ではC++がDよりも優れている点がいくつかあります。おそらくもっとたくさんありますが、ここにいくつか挙げておきたいことがあります。
C++には、考え抜かれた型システムがあります
現時点では、Dの型システムにはかなりの数の問題があり、設計の見落としのようです。たとえば、constの推移性とpostblitコンストラクターが値型で機能する方法により、構造体にクラスオブジェクト参照またはポインターが含まれている場合、const構造体を非const構造体にコピーすることは現在不可能です。アンドレイは、彼がこれを解決する方法を知っていると言いました、しかし、詳細を与えませんでした。問題は確かに修正可能です(C++スタイルのコピーコンストラクターの導入も1つの修正です)が、現在のところ、言語の主要な問題です。
私を悩ませている別の問題は、論理的なconstの欠如です(つまり、C++のようにmutable
がありません)。これはスレッドセーフなコードを書くのに最適ですが、constオブジェクト内で遅延初期化を行うことを困難にします(不可能ですか?)(最初の呼び出しで戻り値を構築してキャッシュするconst 'get'関数を考えてください)。
最後に、これらの既存の問題を考えると、型システムの残りの部分(pure
、shared
など)が言語の他のすべての要素とどのように相互作用するかが心配になります。使用する。現在、標準ライブラリ(Phobos)はDの高度な型システムをほとんど使用していません。そのため、ストレスがかかる場合に耐えられるかどうかという問題は合理的だと思います。私は懐疑的ですが楽観的です。
C++にはいくつかの型システムイボ(たとえば、非推移的なconst、iterator
とconst_iterator
を必要とする)があるため、かなり醜くなりますが、C++の型システムは部分的に少し間違っていますが、 Dのように仕事を終わらせるのを止めることはありません。
編集:明確にするために、私はC++がより良い考え抜かれた型システムを持っていると信じています-それが理にかなっているとは限りません-基本的に、Dでは、C++にはない型システムのすべての側面を使用することに伴うリスクがあると感じています。
Dは少し便利すぎる場合があります
C++についてよく耳にする批判の1つは、低レベルの問題を隠蔽していることです。 a = b;
のような単純な割り当ては、変換演算子の呼び出し、オーバーロード割り当て演算子の呼び出しなど、コードからはわかりにくいことが多くあります。このような人もいれば、そうでない人もいます。いずれにせよ、Dでは、opDispatch
、@property
、opApply
、lazy
のように、無邪気な見た目を変える可能性があるため、より悪い(より良い?)予期しないものにコードを記述します。
これは個人的には大きな問題だとは思いませんが、この不快感を感じる人もいます。
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とC++のネガティブな点に焦点を合わせました。それはそれが質問された理由ですが、C++がDよりも優れているという記述としてこの投稿を表示しないでください。場所のより大きな投稿を簡単に作成できますDはC++よりも優れています。どちらを使用するかを決めるのはあなた次第です。
私がD開発に参加したとき、C++について知っておくべきことを最もよく知っている人の1人であるという独特の立場にありました。今、私は、Dについて最も知っていることを知っている人の1人であるという、さらに奇妙な立場にいます。私は、これを適切な信用または自慢する権利に対して、私が不思議に思っていると言っているのではありません。この質問に答えるために有利な立場。同じことがウォルターにも当てはまります。
概して、C++(つまり、C++ 2011)がDよりも優れていることを尋ねるのは、「家の掃除に専門家にお金を払えば、彼らが去る場所はどこですか?」という質問と同じくらい矛盾します。以前より汚い?」 C++でDができなかったことができるという価値が何であれ、それは常に私とウォルターにとってはつらい思いのようでした。そのため、ほとんどの場合、C++がDの手の届かない範囲でできることは何もありません。
言語設計でほとんど理解されていないことの1つは(実際にいくつかのことを行う幸運がある人はほとんどいないため)、強制されるエラーが表示されるよりもはるかに少ないことです。私たちの言語ユーザーの多くは、なんらかの構成を見て、「ええ!これは間違っている!彼らは何を考えていたのですか?」と言います。問題の事実は、言語のほとんどの厄介なインスタンスは、すべて健全で望ましいが、基本的に互いに競合または矛盾しているいくつかの基本的な決定の余波であるということです(たとえば、モジュール性と効率、簡潔さ、制御など)。
これらすべてを念頭に置いて、私が考えることができるいくつかのことを列挙し、それぞれについて、Dの選択が他のより高いレベルの憲章を達成したいという欲求からどのように派生するかを説明します。
Dは、すべてのオブジェクトがビット単位のコピーによって移動可能であると想定しています。これにより、少数のデザインがC++に残ります。具体的には、内部ポインター、つまり、内部にポインターを含むクラスを使用するデザインです。 (そのような設計は、効率コストをかけずに、または無視できる程度にDに翻訳できますが、翻訳作業が必要になります。)この決定は、言語を大幅に簡略化し、オブジェクトのコピーをユーザーの介入なしで、または最小限に抑えて、より効率的に行い、全体のコピー構築モラスと右辺値参照は完全に機能します。
Dは、あいまいな性別の型を許可しません(それらが値型か参照型かを判断できません)。このようなデザインはC++では満場一致で排除され、ほとんどの場合間違っていますが、技術的に正しいものもあります。この選択を行ったのは、ほとんどが不正なコードを許可せず、再設計できるほんの一部の正しいコードしか許可しないためです。私たちはそれが良いトレードオフであると信じています。
Dはマルチルート階層を許可しません。ここの以前のポスターは、この特定のトピックについて非常に興奮していましたが、これは十分に根拠のある根拠であり、すべてに共通のルートを持つ階層よりもルートレス階層の明白な利点はありません。
Dでは、例えば投げることはできません。 int。 Throwableを継承するオブジェクトをスローする必要があります。状況はDの方が優れていますが、C++でできることの1つはDができないことです。
C++では、カプセル化の単位はクラスです。 Dでは、これはモジュール(つまり、ファイル)です。 Walterがこの決定を下した理由は2つあります。カプセル化をファイルシステム保護のセマンティクスに自然にマッピングすることと、「友達」の必要性を取り除くことです。この選択は、Dの全体的なモジュール設計に非常によく統合されています。物事をC++のように変更することは可能ですが、そうすると強制されます。 C++のカプセル化スコープの選択は、C++の物理設計にのみ適しています。
1つまたは2つの小さいものが存在する可能性がありますが、全体としてはこれで十分です。
C++よりも客観的に悪いDで多くを見つけるのは非常に困難になると思います。客観的に悪いと言えるDの問題のほとんどは、実装の問題(言語と実装の若さによるものであり、最新の速度で修正されていることが原因です)か、または問題ですサードパーティのライブラリが不足している(時間の経過とともに)。言語自体は一般にC++よりも優れており、言語としてのC++が優れているのは、C++とDが別の方向に進んだトレードオフがある場合、または誰かが主観的な理由を持っている場合です。 1つが他よりも優れていると思います。しかし、言語としてのC++の方が優れている明白な客観的な理由の数は少なく、はるかに少ないでしょう。
実際、言語としてのC++がDよりも優れている理由を考え出すには、本当に頭を痛めなければなりません。一般的に頭に浮かぶのは、トレードオフの問題です。
Dの const は推移的であり、言語には immutable があるため、C++のconst
よりはるかに強力な保証があり、Dはそうではなく、できませんmutable
。 logical const を含めることはできません。したがって、Dのconstシステムで大きな利益を得ることができますが、状況によっては、C++の場合のようにconst
を使用できないだけです。
Dには1つのキャスト演算子しかありませんが、 C++には4 があります(Cキャスト演算子を数えると5)。これにより、一般的なケースではDでのキャストの処理が容易になりますが、実際にwantすると、const_cast
とその兄弟が提供します。しかし、Dは実際には十分強力であり、テンプレートを使用してC++のキャストを実装できます。そのため、本当に必要な場合は、それらを使用できます(ある時点で、Dの標準ライブラリーになることもあります)。
DはC++よりも暗黙のキャストがはるかに少なく、2つの関数が互いに競合していることを宣言する可能性がはるかに高いです(つまり、キャストを使用するか、完全なモジュールパスを指定することによって、どの関数を意味するかを具体的に指定する必要があります) )。時々、それは煩わしいかもしれませんが、あらゆる種類の function hijacking の問題を防ぎます。あなたは本当にあなたが意図している関数を呼んでいることを知っています。
Dのモジュールシステム は、C++の#includes(言うまでもなく、wayのコンパイルが高速です)よりもはるかにクリーンですが、モジュール自体を超えた一種の名前空間。したがって、モジュール内で名前空間が必要な場合は、Javaルートに移動して、クラスまたは構造体で静的関数を使用する必要があります。これは機能しますが、本当に名前空間が必要な場合は、明らかにそうではありません。実際の名前空間と同じくらいクリーンですが、ほとんどの場合、モジュール自体が提供する名前空間はたくさんあります(実際に競合のようなものに関してはかなり洗練されています)。
JavaとC#のように、Dは複数の継承ではなく単一の継承を持っていますが、JavaとC#とは異なり、同じ効果を得るためにいくつかの素晴らしい方法を提供しますC++の多重継承が持つすべての問題(そしてC++の多重継承は、very乱雑になることがあります。Dには interfacesがあるだけでなく、 、ただし string mixins 、 template mixins 、および alias this があるため、最終的な結果はおそらくより強力であり、 C++の多重継承が持つすべての問題があります。
C#と同様に、Dは structs と classes を区切ります。クラスは継承を持ち、Object
から派生した参照型ですが、構造体は継承のない値型です。この分離は良いことも悪いこともある。これは、C++の古典的な スライスの問題 を取り除き、実際に値型である型を、ポリモーフィックであると想定されている型から分離するのに役立ちますが、最初は、区別が煩わしいかもしれません。 C++プログラマー。最終的には、いくつかのメリットがありますが、タイプの扱い方が多少異なります。
classes のメンバー functions は、デフォルトで多態性です。それらを宣言することはできません non-virtual 。それらが可能かどうかを判断するのはコンパイラ次第です(これは、実際に final であり、基本クラスの関数をオーバーライドしていない場合にのみ当てはまります)。そのため、場合によってはパフォーマンスの問題になる可能性があります。ただし、ポリモーフィズムが本当に必要ない場合は、 structs を使用するだけで問題ありません。
Dには組み込み ガベージコレクター があります。 C++の多くの人は、それを深刻なマイナス面であると考えていますが、現在のところ、その実装には深刻な作業が伴う可能性があります。改善は進んでいますが、Javaのガベージコレクターとの比較では明らかに間違いです。ただし、これは2つの要因によって軽減されます。 1つ目は、主にスタックで structs およびその他のデータ型を使用している場合、大きな問題ではありません。プログラムがヒープ上のものを常に割り当てたり割り当て解除したりしていない場合は、問題ありません。 2つ目は、必要に応じて ガベージコレクター をスキップして、Cのmalloc
とfree
を使用することです。回避または注意する必要があるいくつかの言語機能( array slicing など)があり、一部の標準ライブラリは、少なくとも-を使用しないと実際に使用できません- [〜#〜] gc [〜#〜] (特に文字列処理)、ただしあなたはできますゴミを使わずにDで書き込みますあなたが本当にしたい場合はコレクター。賢明なことは、おそらく一般的にそれを使用し、プロファイリングがパフォーマンスの重要なコードに問題を引き起こしていることを示している場合はそれを回避することですが、必要であれば完全に回避することができます。そして [〜#〜] gc [〜#〜] の実装の品質は時間とともに改善され、 [〜#〜] gc [を使用することによる懸念の多くを排除します〜#〜] が原因となる場合があります。したがって、最終的には [〜#〜] gc [〜#〜] はそれほど大きな問題にはならず、Javaとは異なり、必要に応じてそれを回避できます。
おそらく他にもあるでしょうが、それは私が現時点で思いつくことができるものです。そして、気づくとしたら、それらはすべてトレードオフです。 Dは、C++とは異なる方法でいくつかのことを行うことを選択しました。C++が行う方法よりも明確な利点がありますが、いくつかの欠点もあります。どちらが良いかは、何をしているのかに依存します。多くの場合、最初はおそらく悪化しているように見え、慣れれば問題はありません。どちらかといえば、Dの問題は一般的に、他の言語がこれまでに行ったことのない、またはDが行ったようにまったく行っていない新しいものによって引き起こされる新しい問題です。全体として、DはC++の間違いから非常によく学びました。
そして、言語としてのDはC++よりも多くの点で改善されているので、Dの方が客観的に優れているのが一般的だと思います。
Dには 条件付きコンパイル があります。これは、C++でプログラミングしているときによく見逃す機能の1つです。 C++がそれを追加する場合、C++はテンプレートなどに関しては飛躍的に向上します。
Dには コンパイル時のリフレクション があります。
変数はデフォルトではスレッドローカルですが、必要に応じてshared
にすることもできます。これにより、C++よりもスレッドfarの処理がよりクリーンになります。あなたは完全にコントロールしています。 immutable
と メッセージパッシング を使用してスレッド間で通信するか、変数をshared
にして、ミューテックスと条件変数を使用してC++で行うことができます。 synchronized の導入により、C++よりもさらに改善されています(C#およびJavaと同様)。したがって、Dのスレッド化状況は、C++よりもfarです。
Dのテンプレート はC++のテンプレートよりもはるかに強力であり、はるかに簡単にはるかに多くのことができます。また、テンプレート制約が追加されているため、エラーメッセージはC++の場合よりもway優れています。 Dはテンプレートを非常に強力で使いやすくします。 Modern C++ Design の作者がDの主要な協力者の1人であることは偶然ではありません。 C++テンプレートはDテンプレートと比較して非常に不足していることがわかりました。C++でプログラミングするとき、それは時に非常にイライラすることがあります。
Dには組み込み 契約プログラミング があります。
Dには組み込みの 単体テスト フレームワークがあります。
Dには、string
(UTF-8)、wstring
(UTF-16)、およびdstring
(UTF-32)を使用したユニコードの組み込みサポートがあります。ユニコードの扱いが簡単になります。 string
だけを使用し、一般にユニコードについて心配する必要がない場合は、できます。ただし、ユニコードの基本をある程度理解していれば、いくつかの標準ライブラリ関数が役立ちます。
Dの operator overloading はC++よりも優れているため、1つの関数を使用して複数の演算子を同時にオーバーロードできます。この主な例は、基本的な算術演算子をオーバーロードする必要があり、それらの実装が演算子を除いてまったく同じ場合です。文字列ミックスインはそれを簡単にし、それらすべてのための1つの単純な関数定義を持つことができます。
Dの配列 は、C++の配列よりもはるかに優れています。長さのある適切なタイプであるだけでなく、それらを追加したり、サイズを変更したりできます。それらを連結するのは簡単です。そして何よりも、それらには slicing があります。そして、それは効率的な配列処理のためのhuge恩恵です。文字列はDの文字の配列であり、Dの配列は非常に強力であるため、問題にはなりません(実際、それは素晴らしいことです)。
私は何度も行くことができました。 Dが提供する改善の多くは小さなものです(コンストラクタ名にthis
を使用する、セミコロンが本体全体であるifステートメントやループ本体を許可しないなど)が、それらのいくつかはかなり大きく、それをすべて一緒に追加すると、はるかにプログラミング体験が向上します。 C++ 0xは、Cが欠けていたDの機能の一部を追加します(例:auto
およびlambdas)。ただし、すべての機能が改善されたとしても、C++について客観的に優れている機能はまだ多くありませんDよりも言語として.
お互いを好きになる主観的な理由がたくさんあり、Dの実装の相対的な未熟さが問題になる場合があることは間違いありません(ただし、特にリポジトリが移動されて以来、非常に急速に改善されていますが)。 github )、そしてサードパーティのライブラリの欠如は間違いなく問題になる可能性があります(Dが簡単に C関数を呼び出す -そして、より少ない範囲で C++ functions -間違いなく問題を軽減します)。しかし、それらは言語自体の問題ではなく、実装の品質の問題です。また、実装の品質の問題が修正されると、Dを使用するほうがはるかに快適になります。
したがって、この質問に対する短い答えは「非常に少ない」と思います。言語としてのDは、一般にC++より優れています。
D 2.0では、スタックでクラスインスタンスを割り当てるときにscope
キーワードの値が削除されたため、スタックでRAIIを実行できません。
Dでは値型の継承を実行できないため、事実上、あらゆる形式のRAIIのヒープ割り当てを強制する必要があります。
つまり、emplace
を使用しない限り、手動でメモリを割り当てる必要があるため、veryを使用するのは面倒です。 (Dでemplace
を使用するのがまだ実用的かどうかはまだわかりません。)
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...
とArgs
、args...
と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));
};
}
}
そして、それらはほとんど同じに見えますが、元の受け入れられたany呼び出し可能オブジェクトに対して、delegate
が必要になります。 (C++ 0xバージョンはstd::function
オブジェクトを必要とするため、どちらの方法でも、入力がより冗長で制限的です...冗長性が好きなら良いかもしれませんし、そうでなければ悪いかもしれません。)
私はDについてはあまり知りませんが、私が知っている多くのC++プログラマーはそれを大いに嫌っています。個人的には同意する必要があります。
なぜDがそれほど勢力を得ていないのかを理解するには、まずC++に人々を引き付けるものを理解する必要があります。つまり、一番の理由はコントロールです。 C++でプログラミングすると、プログラムを完全に制御できます。標準ライブラリを置き換えたいですか?あなたはできる。安全でないポインタキャストをしたいですか?あなたはできる。 const-correctnessに違反したいですか?あなたはできる。メモリアロケータを置き換えたいですか?あなたはできる。タイプに関係なく生のメモリをコピーしたいですか?あなたが本当にしたい場合。複数の実装から継承したいですか?それはあなたの葬式です。地獄、ベームコレクターのようなガベージコレクションライブラリを取得することもできます。次に、パフォーマンスなどの問題が発生します。これは、制御に密接に従うものです。プログラマーが制御できるほど、プログラマーはプログラムをより最適化できます。パフォーマンスは、C++を使い続ける主な理由の1つです。
少し調べてみて、それを試したことのある2人の人々に話しかけると、次のようなことがわかります。
統合型階層。 C++ユーザーが継承を使用することはめったになく、ほとんどのC++プログラマーは合成を好みます。そうする理由が非常にある場合に限り、型は継承を通じてリンクされるべきです。オブジェクトの概念は、すべての型をリンクすることにより、この原則に強く違反しています。さらに、これはC++の最も基本的な原則の1つに違反しています。必要なものだけを使用します。 Objectからの継承に関する選択肢が与えられないこと、およびそれに伴うコストは、プログラマーがプログラムを制御できるようにするという点で、C++が言語として何を表しているかに強く反対します。
関数やデリゲートの問題について聞いたことがあります。どうやら、Dには両方の関数とデリゲートがランタイムの呼び出し可能な関数型としてあり、それらは同じではありませんが、交換可能または何か... ?私の友人は彼らとかなりの数の問題を抱えていました。これは間違いなくC++からのダウングレードであり、std::function
があるだけで完了です。
次に、互換性があります。 DはC++と特に互換性がありません。つまり、no言語はC++と互換性があります、正直に言いましょう。C++/CLIは不正行為の一種ですが、エントリへの障壁として、言及する必要があります。
次に、他にもいくつかあります。たとえば、Wikipediaのエントリを読んでください。
import std.metastrings;
pragma(msg, Format!("7! = %s", fact_7));
pragma(msg, Format!("9! = %s", fact_9));
printf
は、これまでに考案された中で最も安全でない関数の1つであり、古いC標準ライブラリのgets
のような大きな問題と同じファミリです。スタックオーバーフローで検索すると、誤用に関する多くの質問が見つかります。基本的に、printf
は [〜#〜] dry [〜#〜] の違反です-形式文字列で型を指定し、それは議論です。 DRYの違反。間違った場合、非常に悪いことが起こります。たとえば、typedefを16ビット整数から32ビット整数に変更した場合です。これも拡張できません。だれもが独自の形式指定子を発明した場合に何が起こるかを想像してみてください。C++のiostreamは遅く、演算子の選択は最大ではない可能性があり、インターフェイスは機能を使用できますが、安全であることが基本的に保証されています。 DRYは違反されておらず、簡単に拡張できます。これはprintf
について言えることではありません。
多重継承はありません。これはC++の方法ではありませんではありません。 C++プログラマーはプログラムを完全に制御することを期待しており、継承できないものを強制する言語はその原則に違反しています。さらに、デフォルトの実装などを提供するためにインターフェースからクラスに型を変更すると、すべてのユーザーのコードが突然壊れるため、継承が(さらに)脆弱になります。それは良いことではありません。
別の例は、string
およびwstring
です。 C++では、それらの間で変換する必要があり、このライブラリはUnicodeをサポートしています。この古いCライブラリはconst char*
のみを使用し、文字列引数の型に応じて同じ関数の異なるバージョンを記述する必要があります。欲しいです。特に、たとえばWindowsヘッダーには、独自のコードを妨害する可能性のある問題に対処するために、非常に苛立たしいマクロがいくつかあります。ミックスにdstring
を追加しても事態はさらに悪化します。2つの文字列タイプではなく、3つを管理する必要があるためです。複数の文字列型があると、メンテナンスの負担が増え、文字列を処理する反復的なコードが導入されます。
スコット・マイヤーズは書いている:
Dは、プログラマーが最新のソフトウェア開発の課題に取り組むのを支援するために構築されたプログラミング言語です。これは、正確なインターフェイス、緊密に統合されたプログラミングパラダイムの連携、言語によるスレッドの分離、モジュール型の安全性、効率的なメモリモデルなどを介して相互に接続されたモジュールを促進することによって行われます。
言語によるスレッドの分離はプラスではありません。 C++プログラマーはプログラムを完全に制御することを期待しており、何かを強制する言語は、医師が注文したものとはまったく異なります。
また、コンパイル時の文字列操作についても触れます。 Dには、コンパイル時にDコードを解釈する機能があります。これはプラスではありません。すべてのベテランC++プログラマーによく知られている、Cの比較的限定されたプリプロセッサーによって引き起こされる大規模な頭痛を考慮して、この機能がいかに悪用されるか想像してみてください。コンパイル時にDコードを作成する機能はすばらしいですが、構文ではなくsemanticである必要があります。
また、一定の反射が期待できます。 Dにはガベージコレクションがあり、C++プログラマはJavaやC#などの言語に哲学でかなり直接反対しています。構文の類似性がそれらを思い起こさせます。これはそうではありません。必然的に客観的に正当化できますが、それは確かに注意されるべきものです。
基本的に、C++プログラマーがまだできないことの多くは提供されていません。多分Dで階乗メタプログラムを書く方が簡単かもしれませんが、私たちはcanをすでにC++で階乗メタプログラムを書いています。たぶんDでは、コンパイル時のレイトレーサーを書くことができますことができますが、とにかく誰もそれをしたくありません。 C++哲学の根本的な違反と比較して、Dでできることは特に注目に値しません。
これらが表面上の問題だけであるとしても、表面上、Dが実際にはC++のように見えないという事実は、多くのC++プログラマーがDに移行していないことのおそらく良い理由であると確信しています。おそらく、Dは自分自身を宣伝するより良い仕事をする必要があります。
C++がDよりも「優れている」ことで最も重要なことは、レガシーライブラリとのインターフェイスです。さまざまな3Dエンジン、OpenCLなど。 Dは新しいため、選択できるライブラリの数ははるかに少なくなっています。
C++とDのもう1つの重要な違いは、C++に複数の財政的に独立したベンダーがあることですが、2014年の時点で、Dには実際には1つしかありません、2 -それを作成した人のチーム。興味深いのは、プロジェクトがテクノロジー、コンポーネントに依存してはならず、ベンダーが1つだけであり、ソフトウェアにさえ当てはまるとは限らないという "第2ソースの原則" であるということです。
比較のため、Rubyインタープリターの最初のバージョンは、Rubyの発明者である松本幸宏によって作成されましたが、2014年の主流のRubyインタープリターは、他の人が実際にゼロから作成しました。したがって、Rubyは、財政的に独立した複数のベンダーを持つ言語と見なすことができます。一方、Dは素晴らしいテクノロジーですが、それを開発する少数の開発者に依存しています。
Javaの歴史によれば、テクノロジー(この場合はJava)に優れた単一の金融機能があっても、大規模な企業ユーザーに関係なく、そのテクノロジーが本質的にダンプされるという大きなリスクがあります。ベース。 Apache Software Foundation の引用。ECは「Executive Committee」を表しています。
オラクルはECにJava SE 7仕様の要求とライセンスを提供しましたが、これは自己矛盾し、仕様の独立した実装の配布を厳しく制限し、最も重要なのは仕様の独立したオープンソース実装の配布
歴史的なメモとして、Javaアプレットは、HTML5 WebGLが開発される何年も前にハードウェアアクセラレーション3Dキャンバスを持っていたと言えます。 Javaがコミュニティプロジェクトであった場合、Javaアプレットの起動速度の問題は解決された可能性がありますが、Javaの唯一の投資家であるSun Microsystemsの幹部は、 Javaの実装を修正するほど重要ではない。最終結果:Java GUIフレームワーク(Swingなど)の「貧者のレプリカ」としての複数のベンダーによるHTML5キャンバス。興味深いことに、サーバー側のPythonプログラミング言語には、Javaが約束したのと同じ利点があります。1回の書き込みで、ハードウェアに関係なく、すべてのサーバーで実行できます。ただし、Pythonアプリケーションはマシンコードにコンパイルされていません。 PythonはJavaとほぼ同じくらい古いものですが、Javaとは異なり、複数の独立して資金調達された開発者チーム(PyPyとメインストリーム_)によってバックアップされています。Pythonインタプリタ)。
まとめ:
生産用のテクノロジーを評価する場合、テクノロジーの最も重要な特性は、それを開発する人々、開発が行われる社会的プロセス、および財政的に独立した開発チームの数です。
テクノロジーT1をテクノロジーT2よりも使用する方が有利かどうかは、テクノロジーのベンダーに依存し、テクノロジーT1がプロジェクト関連の問題をT2よりも安価に解決できるかどうかに依存します。たとえば、単一のサプライヤの問題が無視された場合、Javaバイナリは展開時に再コンパイルする必要がないため、情報システムの場合、JavaはC++よりも「優れた」テクノロジーになります。新しいハードウェアとメモリ管理関連のソフトウェア開発作業の量は、C++の場合よりもJavaの場合の方が少なくなります。ゼロから開発されたプロジェクト。他のライブラリに依存しないプロジェクトは、C++よりもDで開発する方が安上がりですが、一方でC++には複数のベンダーがあるため、長期的にはリスクが低くなります。 (Javaの例では、Sun Microsystemsはほとんど問題ありませんでしたが、Oracleは実際にJavaを「新しいCOBOL」にしました。)
C++の制限のいくつかに対する可能な回避策
C++のいくつかの制限に対する考えられる回避策の1つは、最初のタスクが断片に行われ、断片が「ソート」される(分類、クラスター化、分割、その他の便利な言葉)設計パターンを使用することです。同じもの)から2つのクラス:制御ロジック関連のタスク、メモリアクセスパターンではローカリティは許可されません。 信号処理のようなタスク、局所性が簡単に達成されます。信号処理「ライク」タスクは、比較的単純なコンソールプログラムのセットとして実装できます。制御ロジック関連のタスクはすべて、RubyまたはPythonまたはその他の何かで記述された単一のスクリプトに配置され、ソフトウェア開発の快適さは速度よりも優先されます。
高価なオペレーティングシステムプロセスの初期化とオペレーティングシステムプロセス間のデータコピーを回避するために、小さなC++コンソールアプリケーションのセットは、Ruby/Pythonなどによって「サーブレット」として起動される単一のC++プログラムとして実装される場合があります。脚本。 Ruby/Python /など。スクリプトは、終了する前にサーブレットをシャットダウンします。 「サーブレット」とRuby/Python /などとの間の通信。スクリプトは、Linux名前付きパイプまたは同様のメカニズム上で実行されます。
最初のタスクが、前述の2つのクラスに分類できる部分に簡単に分割できない場合は、問題を言い換えて、最初のタスクを変更する必要があります。
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()
引数をref
としてマークすることで、C++に非常に近づくことができます(クラスは参照型と構造体は、C#と同様に、Dの値型です。
代わりに、クラスのNonNullable
テンプレートをD標準ライブラリ構成として作成する計画があると思います。それでも、NonNullable(Type)
と比較して_Type&
_の簡潔さを気に入っており、デフォルトとしてnull不可を優先します(Type
やNullable(Type)
のようなものをレンダリングします) )。しかし、それをDのために変更するのは遅すぎ、私は今話題から外れています。