英語版
このページの英語版を見る

概要

Dとは何か?

D Man

Dは汎用のシステムおよびアプリケーション・プログラミング言語である。 高レベル言語でありながら、高性能なコードを書く能力を保持している。 高性能なコードを記述し、オペレーティング・システムと直接インターフェイスする能力を保持している。 オペレーティング・システム API およびハードウェアと直接インターフェイスする能力を保持している。 Dは中規模から大規模のプログラムを書くのに適している。 万行のプログラムを開発者チームで書くのに適している。Dは習得が容易である。 Dは習得が容易で、プログラマーを支援する多くの機能を備えている、 また、積極的なコンパイラ最適化技術に適している。

D言語はスクリプト言語でもインタプリタ言語でもない。 また VMもない、 宗教があるわけでもない。 哲学もない。実用的なプログラマーのための実用的な言語なのだ。 素早く、確実に仕事をこなし、保守可能で理解しやすいコードを残す必要がある 保守可能で理解しやすいコードを残す必要がある。

Dは、多種多様な言語のコンパイラを実装し コンパイラを実装し、それらの言語を使って大規模なプロジェクトを構築しようとした数十年の経験の集大成である。 Dは、多種多様な言語用のコンパイラを実装し、それらの言語を使って大規模なプロジェクトを構築しようとした数十年の経験の集大成だ。Dはこれらの言語(特にC++)からインスピレーションを得ている。 Dは、そうした他の言語(特にC++)からインスピレーションを受け、それを経験と実世界での実用性で和らげる。 経験と実世界での実用性を加味している。

なぜDなのか?

確かにそうだ。他のプログラミング言語が必要だろうか?

ソフトウェア業界は猛烈なスピードで進化し続けている。 新しいアイディアが登場し、古いアイディアが検証されたり捨てられたりする。 プログラマーがプログラミング言語に求めるものは変化する。 利用可能なメモリとコンピューティング・パワーは桁外れに増大している。 また、開発されるプログラムの規模も桁違いに大きくなっている。

コンパイラーはもはや、利用可能なコンピューティング・リソースに大きく制約されることはない。 そのため、プログラマーのために多くのことができるようになった。 より強力な言語機能が実用的になった。 これらの機能を既存の言語に後付けするのは難しいかもしれない、 これらの機能が十分にあれば、新しい言語が正当化される。

Dの主な設計目標

言語を設計する上で、すべてはトレードオフである。いくつかの いくつかの原則を念頭に置くことは、正しい決断を下すのに役立つ。

  1. 高速で効果的なコードをわかりやすく書けるようにする。
  2. コンパイラからコンパイラへ、マシンからマシンへ、オペレーティング・システムからオペレーティング・システムへ移植可能なコードを書きやすくする。 コンパイラからコンパイラへ、マシンからマシンへ、オペレーティング・システムからオペレーティング・システムへ移植可能なコードを書きやすくする。 システム間で移植可能なコードを書きやすくする。未定義の動作や処理系の定義:" をできるだけ排除する。 をできるだけ排除する。
  3. よくある間違いをなくすか、少なくとも減らすような構文的・意味的構造を提供する。 よくあるミスを少なくとも減らす。サードパーティの静的コードチェッカーの必要性を減らすか、あるいはなくす。 サードパーティの静的コードチェッカの必要性を減らす。
  4. メモリーセーフプログラミングをサポートする。
  5. マルチパラダイム・プログラミングをサポートする。 命令型、構造型、オブジェクト指向、ジェネリック、さらには 関数型プログラミング・パラダイムをサポートする。
  6. 間違った方法よりも正しい方法の方が簡単である。
  7. C、C++、Javaでのプログラミングに慣れているプログラマーにとって、学習曲線が短いこと。 C、C++、またはJavaでのプログラミングに慣れているプログラマーにとって、学習曲線が短いこと。
  8. 必要に応じて、低レベルのベアメタルアクセスを提供する。高度なプログラマーが 上級プログラマが必要に応じてチェックを逃れる手段を提供する。
  9. ローカルのCアプリケーション・バイナリ・インターフェースと互換性がある。
  10. DコードがCコードと同じに見える場合は、同じ動作をするか、エラーを出すようにする。 同じ動作をさせるか、エラーを出させる。
  11. 文脈自由文法を持つ。構文解析を成功させるためには 意味解析を必要としないこと。
  12. 国際化されたアプリケーションの作成を容易にサポートする。
  13. 契約プログラミングとユニットテスト手法を取り入れること。
  14. 軽量でスタンドアロンなプログラムを構築できること。
  15. ドキュメント作成のコストを削減する。
  16. コンパイラ最適化技術の進歩を可能にする十分なセマンティクスを提供する。 技術に対応する。
  17. 数値解析プログラマーのニーズに応える。
  18. もちろん、これらの目標が矛盾することもある。解決策は 使いやすさを優先する。

Dへの移行

Dの一般的な外観はCやC++に似ている。そのため C/C++からDへの移行は自然に感じられるはずだ。 プログラマーは プログラマーは、まったく新しいやり方を学ぶ必要はない。

Dを使うことは、プログラマーがJava vmや仮想マシンのような特殊なランタイムvm(仮想マシン)に制限されることを意味しない。 Dを使うことは、プログラマーがJava vmやSmalltalk vmのような特殊なランタイムvm(仮想マシン)に制限されることを意味しない。 のような特殊なランタイムvm(仮想マシン)に制限されることはない。 D vmは存在しない。 リンク可能なオブジェクト・ファイルを生成する。 DはCと同じようにオペレーティング・システムに接続する。 make Dは、Cと同じようにオペレーティング・システムに接続する。 Dでの開発にぴったりだ。

残すべき機能

Dは誰のためにあるのか?

Dは誰のためにあるのか?

Dの主な特徴

このセクションでは、様々なカテゴリーにおけるD の興味深い機能をさまざまなカテゴリーに分けて紹介する。

オブジェクト指向プログラミング

クラス

Dのオブジェクト指向はクラスからきている。 継承モデルは、インターフェイスで強化された単一継承である。 インターフェースで強化されている。クラスObjectは継承階層のルートに位置する。 クラスが継承階層のルートに位置する。 を実装している。 クラスは参照によってインスタンス化される。 クラスは参照によってインスタンス化される。 は必要ない。

詳しくはクラスのページを参照のこと。 を参照のこと。

演算子オーバーロード

新しい型をサポートするように型システムを拡張するために、既存の演算子と連動するクラスを作ることができる。 新しい型をサポートするために型システムを拡張する。例としては、次のようなものがある。 をオーバーロードして、通常の代数構文を使えるようにする。 をオーバーロードして、通常の代数構文を使えるようにする。

演算子オーバーロード」のページを参照のこと。 のページを参照のこと。

関数型プログラミング

関数型プログラミングには、カプセル化という点で多くの利点がある、 関数型プログラミングには、カプセル化、並行プログラミング、メモリ安全性、コンポジションなど、多くの利点がある。関数型プログラミングに対する Dは関数型プログラミングをサポートしている:

生産性

モジュール

ソース・ファイルはモジュールと1対1で対応している。

モジュール のページを参照のこと。

宣言と定義

関数とクラスは一度だけ定義される。前方参照される場合は 宣言は必要ない。 モジュールはインポートすることができ、そのすべてのパブリック宣言はインポーターが利用できるようになる。 をインポートすることができる。

例:

class ABC
{
    int func() { return 7; }
    static int z = 7;
}
int q;

すべてのメンバはクラスまたは構造体の中で定義され、個別に定義されることはない。

class Foo
{
    int foo(Bar c) { return c.bar; }
}

class Bar
{
    int bar() { return 3; }
}

D関数がインライン化されるかどうかは、オプティマイザの設定によって決まる。 オプティマイザの設定によって決まる。

テンプレート

Dテンプレートは、ジェネリック・プログラミングをサポートしながら、部分的な特殊化の力を提供するクリーンな方法である。 部分的な特殊化の力を提供する。 テンプレート・クラスとテンプレート関数が利用できる。 可変長引数やタプルも利用できる。

テンプレート のページを参照のこと。

連想配列

連想配列とは、整数インデックスに限定されず、任意のデータ型をインデックスとする配列のことである。 をインデックスとする配列である。 要するに、連想配列はハッシュ・テーブルである。連想 配列は、高速で効率的でバグのないシンボル・テーブルを簡単に構築できる。 テーブルを簡単に構築できる。

連想配列 のページを参照のこと。

ドキュメンテーション

ドキュメンテーションは伝統的に2回行われてきた。 まず、その関数が何をするのかを説明するコメントがある。 その後、別のhtmlやmanページに書き換える。 そして当然ながら、時間が経つにつれて、コードが更新されても別のドキュメントが更新されないため、両者は乖離する傾向がある。 が更新され、別のドキュメントが更新されなくなる。 ソースに埋め込まれたコメントから、必要な洗練されたドキュメントを直接生成することができる。 ソースに埋め込まれたコメントから、必要な洗練されたドキュメントを直接生成することができれば、ドキュメントの準備に必要な時間を半分に短縮できるだけでなく、次のような利点もある。 ドキュメントの準備に必要な時間を半分に短縮できるだけでなく、次のことも容易になる。 ドキュメントをコードと同期させることができる。 DdocはD ドキュメント・ジェネレーターの仕様である。このページもDdocによって生成された。

サードパーティ製のツールは他の言語にも存在する。 これらにはいくつかの重大な欠点がある:

関数

D言語は、以下のような通常の関数をサポートしている。 グローバル関数、オーバーロード関数、関数のインライン化、 メンバ関数、仮想関数、関数ポインタなどである。 加えて

ネストされた関数

関数は他の関数の中に入れ子にすることができる。 これは、コード・ファクタリング、局所性、関数クローズ・テクニックに非常に有用である。 関数クロージャのテクニックに大いに役立つ。

関数リテラル

匿名関数は式に直接埋め込むことができる。

ダイナミック・クロージャー

ネストされた関数やクラスのメンバ関数は、クロージャ(デリゲートとも呼ばれる)で参照することができる。 クロージャ(デリゲートとも呼ばれる)で参照できる。 をより簡単に、型安全にする。

イン、アウト、レフ・パラメーター

を指定することで、関数をより自己文書化しやすくするだけでなく、ポインタの必要性もほとんどなくなる。 ポインタの必要性がほとんどなくなる。 ポインタの必要性がほとんどなくなる。 また、コーディング上の問題を発見するためにコンパイラが手助けしてくれる可能性が広がる。

これにより、Dはより多様な海外APIと直接インターフェイスできるようになった。 Dがより多様な海外APIと直接インターフェイスできるようになる。インターフェイス定義言語」のような回避策は必要ない。 インターフェース定義言語」のような回避策は必要なくなる。

配列

Cの配列には修正可能な欠陥がいくつかある:

D配列には、ポインタ、静的配列、動的配列、連想配列などの種類がある。 配列、そして連想配列である。

詳しくは配列のページを参照のこと。

文字列

文字列操作 は、言語で直接サポートする必要がある。最近の言語では 文字列の連結、コピーなどを扱う。 は、配列処理の改良の直接的な結果である。

レンジ

D言語では、他の言語に見られるイテレーターやジェネレーターの代わりに、レンジという概念を使用している。 の代わりに、範囲という概念を使う。範囲とは、一連の値に対する共通のインターフェイスを提供するあらゆる型のことである。 型のことである。レンジの目的は、任意のデータに対して動作するコードをよりシンプルに記述できるようにすることである。 任意のデータに対して動作するコードをより単純な方法で書けるようにし、それによって再利用性を高めることにある。

最も基本的な型は入力範囲と呼ばれる、 これは3つのメソッドを提供する。

struct MyRange
{
    auto front()
    {
        // 配列の次の値を返す
    }

    void popFront()
    {
        // シーケンスの先頭を次の値に移動する
    }

    bool empty()
    {
        // 返す値がもうない場合はtrueを返す
    }
}

このシンプルなインターフェイスのパワーを理解するために、例を挙げてみよう。 例を見てみよう。例えば、ある会社の全従業員を対象に、40歳以下の従業員を除外し、残りの従業員を次のようなグループに分けるプログラムを書きたいとする。 ある会社の全従業員を取り出し、40歳未満の従業員を除外し、残りの従業員を所属組織別に配列にグループ化するプログラムを書きたいとする。 の配列にグループ化する。

struct Employee
{
    uint id;
    uint organization_id;
    string name;
    uint age;
}

struct Employees
{
    Employee[] data;

    this(Employee[] employees)
    {
        data = employees;
    }

    Employee front()
    {
        return data[0];
    }

    void popFront()
    {
        data = data[1 .. $];
    }

    bool empty()
    {
        return data.length == 0;
    }
}

ここでは、単純な例としてコンストラクターからデータを取得しているが、CSVやデータベースなど、どのようなソースからでも取得できる。 CSVやデータベースのように、どのようなソースからでも来る可能性がある。

D.D.では、基本的な動的配列も範囲として機能する、 Dでは基本的な動的配列も範囲として機能するため、範囲を受け付けるアルゴリズムはすべて配列も受け付けることになる。 Dでは基本的な動的配列も範囲として機能する。しかし、静的配列は範囲とはみなされない、 というのも、popFront の操作は、範囲の長さを変更することに基づいているからだ、 これは静的配列では不可能である。静的配列から範囲を取り出すには、次のようにする、 のように、すべての要素を含むスライスを作成する:

int[4] array = [1, 2, 3, 4]; // 範囲ではない
array[]; // 有効範囲

これで範囲が定義されたので、その範囲に入力し、フィルタリング・コードを書くことができる。

void main()
{
    import std.algorithm.iteration : filter, chunkBy;

    Employees employees = Employees([
        Employee(1, 1, "George", 50),
        Employee(2, 3, "John", 65),
        Employee(3, 2, "David", 40),
        Employee(4, 1, "Eli", 40),
        Employee(5, 2, "Hal", 35)
    ]);

    auto older_employees = employees
        .filter!(a => a.age > 40) // D のラムダは=>構文を使用する
        .chunkBy!((a,b) => a.organization_id == b.organization_id);
}

std.algorithmに含まれるすべてのアルゴリズムは、プロジェクトごとに共通の機能を書き直すという問題を避けるために、範囲を使って動作する。 std.algorithmはソート、フィルター、マップ、リダクションなどを実装している。 はソート、フィルター、マップ、リダクションなどを実装している。

従業員構造体は入力範囲の定義に準拠している、 foreach ループでも使用できる。 渡された値が入力範囲かどうかを自動的に検出する。

foreach(employee; employees)
{
    writeln(employee);
}

と等価である。

for(; !employees.empty; employees.popFront())
{
    writeln(employees.front);
}

レンジの型

入力レンジはレンジの最も基本的な形態に過ぎない。

これらの範囲はそれぞれ、基礎となるデータへのアクセス方法を示している。 これらの範囲はそれぞれ、基礎となるデータにアクセスする明確な方法を表している。出力範囲の場合は、データを別のソースに送信する方法である。 を別のソースに送信する方法である。各範囲の型についての詳細は 範囲プリミティブ のページを参照のこと。

これらの範囲型はそれぞれ、標準ライブラリの異なるアルゴリズムにアクセスできる。 にアクセスできる。例えば、入力範囲に対してフィルタを実行することができる。 で実行できるが、ソートはできない。 スライス演算子オーバーロード "が定義されたランダムアクセス範囲を必要とする。各関数の要件は、以下の関数のシグネチャで確認できる。 各関数の要件は、ドキュメントのテンプレート化された関数のシグネチャで見ることができる。 制約を参照すること。テンプレート ページと上記の範囲プリミティブのリンクを参照のこと。 を参照のこと。

前述したように、Dにおける動的配列と連想配列は範囲として機能する。 の範囲として機能する。具体的には、これらはランダム・アクセス範囲である。 std.algorithmのどの関数も、これらの基本的な型を扱うことができる。

高度なレンジコード

以下の例では、入力範囲と出力範囲を使って、stdinからデータを取り込む。 stdinからデータを受け取り、ユニークな行だけを取り出してソートし、結果を 結果を標準出力に出力する。

// 行を並べ替える
import std.stdio;
import std.array;
import std.algorithm;

void main()
{
    stdin
        .byLine(KeepTerminator.yes)
        .uniq
        .map!(a => a.idup)
        .array
        .sort
        .copy(stdout.lockingTextWriter());

範囲ベースのコードの例については、『Ali. レンジの章を参照のこと。 Çehreliの著書 "Programming In D"のRangesの章を参照のこと。また H. S. Teoh著「Component programming with ranges」も参照のこと。

資源管理

自動メモリー管理

Dメモリの割り当ては完全にガベージコレクションされる。 ガベージコレクションによって、プログラミングはよりシンプルになる。 ガベージコレクションを使えば、面倒でエラーの起きやすいメモリ割り当て追跡コードが不要になる。 ガベージ・コレクションによって、面倒でエラーの起きやすいメモリ割り当ての追跡コードが不要になる。これは次のことを意味するだけではない。 開発時間が大幅に短縮され、メンテナンス・コストが削減される、 その結果、プログラムは頻繁に実行される が速くなる。

これについての詳しい議論は ガベージコレクションを参照のこと。

明示的なメモリー管理

D言語はガベージコレクション言語であるが、newとdeleteは特定のクラスに対してオーバーライドすることができる。 操作を特定のクラスに対してオーバーライドすることができる。 カスタム・アロケータを使うことができる。

RAII

RAIIは、リソースの割り当てと割り当て解除を管理する最新のソフトウェア開発技法である。 RAIIは、リソースの割り当てと割り当て解除を管理する最新のソフトウェア開発手法である。Dは、ガベージコレクションとは独立した、制御された予測可能な方法でRAIIをサポートする、 Dは、ガベージコレクションサイクルから独立した、制御された予測可能な方法でRAIIをサポートする。 サイクルをサポートする。

パフォーマンス

軽量骨材

DはシンプルなC言語のスタイル "構造体"をサポートしている。 Cのデータ構造との互換性を保つためと、クラスをフルに使うのが面倒なときに便利だからだ。 クラスの全パワーが過剰な場合に便利だからだ。

インラインアセンブラ

デバイス・ドライバ、高性能システム・アプリケーション、組み込みシステム、 特殊なコードなどでは、アセンブラ言語が必要になることがある。 に触れる必要がある。D実装はインライン・アセンブラを実装する必要はないが D実装はインライン・アセンブラを実装する必要はないが、インライン・アセンブラは定義されており、言語の一部となっている。 言語の一部である。インライン・アセンブラは定義されており、言語の一部である、 別個のアセンブラやDLLを必要としない。

多くのD実装は、組込み関数もサポートする。 C言語がI/Oポート操作のための組込み関数をサポートしているのと同様である、 特殊な浮動小数点演算への直接アクセスなどである。

インラインアセンブラ」のページを参照のこと。 のページを参照のこと。

信頼性

最新の言語は、プログラマーがコードのバグを洗い出すのを助けるために、できる限りのことをすべきである。 は、プログラマーがコードのバグを洗い出すのを助けるために、できる限りのことをしなければならない。その手助けには様々な形がある; よりロバストなテクニックを使いやすくする、 明らかに正しくないコードをコンパイラがフラグを立てたり、ランタイム・チェックをしたりすることだ。

契約

契約プログラミング (バートランド・メイヤー博士によって考案された)は、次のような手法である。 技術である。 プログラムの正しさを保証する技術である。Dバージョンの 関数の前提条件、関数の後条件、クラスの不変量、アサート契約などがある。 invariants、assert契約などがある。 Dの実装については「契約」を参照のこと。

単体テスト

ユニット・テストをクラスに追加して、プログラム起動時に自動的に実行されるようにすることができる。 に追加することができる。これは、ビルドのたびに、クラスの実装が不注意で壊れていないかどうかを検証するのに役立つ、 これは、ビルドのたびに、クラスの実装が不注意で壊れていないことを確認するのに役立つ。ユニット ユニット・テストは、クラスのソース・コードの一部を形成する。これを作成する を作成することは、クラス開発プロセスの自然な一部となる。 完成したコードをテスト・グループに壁越しに投げるのとは対照的だ。

ユニットテストは他の言語でもできる。 他の言語でもユニットテストはできる。 ユニットテストはD言語の大きな特徴である。 関数が実際に動作することを保証すると同時に、関数がどのように動作するかを説明することができる。 関数が実際に動作することを保証すると同時に、関数の使い方を説明するのにも役立つ。

ウェブ上でダウンロードできる多くのライブラリやアプリケーションのコードベースを考えてみよう。 を考えてみよう。その中に単体テストはおろか 単体テストはおろか、検証テストがまったくないものはどれくらいあるだろうか?通常のやり方は コンパイルできれば動くと考えるのが普通だ。そして、その過程でコンパイラが吐き出す警告は、本当のバグなのか、それとも単なるバグなのか。 コンパイラが吐き出す警告が本当のバグなのか、それとも単なるお喋りなのか。 なのだろうか。

契約プログラミング "と並んで、ユニットテストは、D言語を、信頼性の高い堅牢なシステム・アプリケーションを書くための最高の言語にしている。 は、信頼性が高く堅牢なシステム・アプリケーションを書くのに最適な言語である。 単体テストはまた、私たちの目の前に落ちてきた未知のDコードの品質を、素早く簡単に見積もることもできる。 もしユニットテストもコントラクトもなければ、それは受け入れがたいものだ。 ユニットテストも契約もなければ、それは受け入れがたいものだ。

ユニットテスト のページを参照のこと。

デバッグ属性とステートメント

今やデバッグは言語の構文の一部である。 このコードは、マクロや前処理コマンドを使わずに、コンパイル時に有効にも無効にもできる。 マクロや前処理コマンドを使用することなく、コンパイル時にコードを有効にも無効にもできる。デバッグ構文は以下を可能にする。 一貫性があり、移植性があり、理解しやすい。 実際のソースコードは、デバッグ・コンパイルとリリース・コンパイルの両方を生成できる必要がある。 リリース・コンパイルの両方を生成できる必要がある。

例外処理

単なるtry-catch-finallyモデルではなく、優れたtry-catch-finallyモデルが使われる。 が使われる。デストラクタにfinallyセマンティクスを実装させるためだけにダミー・オブジェクトを作る必要はない。 デストラクタにfinallyセマンティクスを実装させるためだけにダミーオブジェクトを作る必要はない。

同期化

マルチスレッド・プログラミングが主流になりつつある、 Dはマルチスレッド・プログラムを構築するためのプリミティブを提供している。 同期はメソッド・レベルでもオブジェクト・レベルでも行える。

synchronized int func() { ... }

同期関数は、一度に1つのスレッドだけがその関数を実行できる。 その関数を実行することができる。

synchronizeステートメントは、ステートメントのブロックにミューテックスを置く、 オブジェクト単位またはグローバルにアクセスを制御する。

ロバスト技術のサポート

コンパイル時のチェック

ランタイム・チェック

互換性

演算子の優先順位と評価ルール

DはC演算子とその優先規則、評価順序、昇格規則を保持する。 評価ルール、および昇格ルールを保持する。これによって、C言語の演算子に慣れきっているために起こりうる微妙なバグを避けることができる。 これは、C言語のやり方に慣れすぎているために発生する微妙なバグを回避するためである。 のやり方に慣れているために、意味論の違いによるバグを見つけるのに苦労するような微妙なバグを避けることができる。 を見つけるのに非常に苦労することになる。

C APIへの直接アクセス

DはCのデータ型に対応するデータ型を持っているだけではない、 C関数への直接アクセスを提供する。そのため ラッパー関数やパラメータ・スウィズラーを書く必要もないし、集合体メンバをひとつひとつコピーするコードも必要ない。 を書く必要もない。

すべてのCデータ型をサポートする

あらゆるC APIや既存のC言語とのインターフェイスを可能にする。 ライブラリコードとのインタフェースを可能にする。このサポートには、構造体、共用体、列挙型、ポインタ、すべてのC99型が含まれる、 ポインタ、すべてのC99型が含まれる。 Dには以下の機能がある。 Dには、構造体メンバのアラインメントを設定する機能がある。 Dには、構造体メンバのアライメントを設定する機能がある。

OSの例外処理

Dの例外処理メカニズムは、以下のようなOSの例外処理方法に対応している。 の例外処理メカニズムに接続する。 に接続する。

既存のツールを使う

Dは標準的なオブジェクト・ファイル形式でコードを生成する。 標準的なアセンブラ、リンカ、デバッガ、プロファイラ、exeコンプレッサを使用できる、 また、他の言語で書かれたコードとリンクすることもできる。 また、他の言語で書かれたコードとリンクすることもできる。

プロジェクト管理

バージョン管理

Dは、同じテキストから複数のバージョンのプログラムを生成する の生成をサポートしている。これは、Cプリプロセッサ #if/#endifテクニックに取って代わる。

非推奨

時間の経過とともにコードが進化するにつれて、古いライブラリ・コードの一部は新しいバージョンに置き換えられる。 より新しく、より良いバージョンに置き換えられる。古いバージョンは、レガシーコードをサポートするために 古いバージョンは、レガシーコードをサポートするために利用可能でなければならないが、非推奨とマークすることもできる。 非推奨のバージョンを使用するコードは、通常、違法と判定される。 しかし、コンパイラー・スイッチによって許可される。 これにより、メンテナンス・プログラマーは プログラマーは、非推奨機能への依存を特定しやすくなる。

サンプルDプログラム(sieve.d)

/* Sieve of Eratosthenes prime numbers */

import std.stdio;

void main()
{
    size_t count;
    bool[8191] flags;

    writeln("10 iterations");

    // iterを捨て変数として使う
    foreach (iter; 1 .. 11)
    {
        count = 0;
        flags[] = 1;

        foreach (index, flag; flags)
        {
            if (flag)
            {
                size_t prime = index + index + 3;
                size_t k = index + prime;

                while (k < flags.length)
                {
                    flags[k] = 0;
                    k += prime;
                }

                count += 1;
            }
        }
    }

    writefln("%d primes", count);
}

注意:配列のインデックスx が数値xを表していると予想されるかもしれないが、i + i + 3 は一見奇妙に見える。 しかし、それぞれのインデックスを考えてみると、最初の要素は0 + 0 + 3 = 3を表すことになる; 番目の要素は1+1+3=5を表す; 3番目の要素は2+2+3=7を表す; といった具合である。 つまり、この配列で表される数字は、実際には3から(8190 + 8190 + 3)、つまり16383までとなる。