言語の機能 vs ライブラリによる実装
D では、 他の言語(例えばC++)ではライブラリとして実装されているような機能も、 言語そのものの機能として組み込んでいるものがいくつかあります:
- 動的配列
- 文字列
- 連想配列
- 複素数
これを有用な特徴ではなく、 言語の肥大化の証拠と考える方もいらっしゃるようです。 何故、これらそれぞれを標準ライブラリの型として実装しなかったのでしょうか?
まず一般的な観点から幾つか理由をあげます:
- どれも非常によく使われています。従って、例え小さくても、 使い勝手の改善は実現するだけの価値があります。
- 言語のコア機能とするということは、その型が不正に使用されていたときに、 コンパイラによって より適切なエラーメッセージを出すことが可能になります。 ライブラリによる実装では、 実装の内部詳細にもとづいたなんだかよくわからないメッセージになる傾向があります。
- ライブラリによる実装では、新しい構文や新しい演算子、 新しいトークンを導入できません。
- ライブラリによる実装は、毎回のコンパイルのたびに、 実装の処理でコンパイル時間を消費する傾向にあります。 結果、全体のコンパイル速度が低下します。
- ライブラリ実装はエンドユーザに柔軟性を提供するとされています。 しかし、それが標準化されると、 コンパイラ内で標準ライブラリを特別なものとして認識・処理することが許され (C++標準は実際にこれを認めています)、 言語組み込みの機能と同じ程度の柔軟さになってしまうのです。
- ライブラリによって新しい型を定義する機能は、 近年急速に発展してはいるものの、 まだまだ既存の言語にスムーズに統合するには遠いところにあります。 荒削りでぎこちない構文と、奇妙な境界例にあふれています。(※訳注: いまいち意味がわからないまま訳してます(^^;。原文は The ability to define new library types, while having greatly advanced in the last few years, still leaves a lot to be desired in smoothly integrating it into the existing language. Rough edges, clumsy syntax, and odd corner cases abound. )
それぞれの項目毎にもっと突っ込んで考えると…:
動的配列
C++ は組み込みの配列があります。ですが、あまり使い勝手はよくありません。 これを改善するのではなく、いくつか異なる配列型が C++ 標準テンプレートライブラリの中に作られ、 組み込み配列の様々な短所をそれぞれでカバーするようになりました。 そのような拡張配列型には、次のようなものがあります:
- basic_string
- vector
- valarray
- deque
- slice_array
- gslice_array
- mask_array
- indirect_array
組み込みの配列を改善することによって、これら変種の必要性は消えて無くなります。 これら全てをカバーする唯一の配列型があって、 学ぶ必要があるのは一つだけになり、 ある配列を別の種類の配列として使いたい時の問題もなくなります。
通常、型を組み込みとすると、シンタックスシュガーを用意できるようになります。 まず、配列リテラルがありますし、次に配列操作のために用意された演算子があります。 ライブラリによる配列実装だと、 既存の演算子をオーバーロードして使わなければなりません。 まず添字演算子 a[i]、これはC++と共通です。 さらに、配列結合演算子 ~、配列追記演算子 ~=、配列スライス演算子 a[i..j]、 そして配列ベクトル演算演算子 a[] が加わりました。
結合演算子 ~ と ~= によって、既存の演算子をオーバーロードしなければならないことに 起因する問題が解決されます。通常、ライブラリ実装による結合演算子には + が採用されます。 しかしこれは、配列のベクトル加算という + の意味と衝突します。 さらいに、結合はもともと足し算とは関係のない概念で、 両方に同じ演算子を使うのは 混乱の元です。
文字列
C++のstd::stringとの詳細な比較 があります。
C++ にももちろん、charの配列と文字列リテラルという形で、 組み込みの文字列サポートがあります。問題は単に、 C++の組み込みの配列が貧弱だという点です。
でも、文字列が文字の配列でないとしたら、いったい何なのでしょうか。 もし組み込みの配列の問題点が解消されたら、同時に文字列の問題も解決するのでしょうか? その通り、解決します。最初は D に文字列クラスがないことを奇妙に感じるかもしれませんが、でも結局、 文字列の操作とは文字の配列の操作に他ならないのです。 もし配列が十分な機能を持っているなら、それ以上のものを加える必要はありません。
さらに、文字列リテラルが ライブラリの文字列クラス型と違う型を持つことによって生じる不自由さも これで無くなります。
連想配列
主な利点は、これも、シンタックスシュガーにあります。 型 T をキーとして int の値を格納する連想配列は、 自然にこう書けます:
int[T] foo;
次のような複雑な書き方にはなりません:
import std.associativeArray; ... std.associativeArray.AA!(T, int) foo;
連想配列を言語の機能としてもっておけば、 しばしばリクエストされる機能である 連想配列リテラル を将来的に実装できる可能性があります。
複素数
C++のstd::complexとの詳細な比較があります。
最大の理由は、 Cの虚数型や浮動小数点数型との互換性を保つためです。 第二の理由は、複素数リテラルを書けるようにするためです。 こう書ける方が:
c = (6 + 2i - 1 + 3i) / 3i;
こう書くより:
c = (complex!(double)(6,2) + complex!(double)(-1,3)) / complex!(double)(0,3);
ずっと楽ではありませんか?