ミックスイン
ミックスイン (テンプレート・ミックスイン とは別物です) は、文字列定数を通常の D のコードとしてコンパイルし、 プログラムへと挿入する機能です。 この機能をコンパイル時の文字列操作と組み合わせると、 ドメイン特化言語 (DSL) を作ることも可能になります。
例えば以下の例は、 指定された名前のメンバを持つ構造体を生成するテンプレートです:
template GenStruct(char[] Name, char[] M1) { const char[] GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } mixin(GenStruct!("Foo", "bar"));
以下のコードが生成されます:
struct Foo { int bar; }
Dのミックスインはテキストを操作して結果をコンパイルに使うわけですから、 表面的には、C のプリプロセッサと似た面もあります。 しかし、重大かつ根本的な違いが存在します。
- C のプリプロセス処理は字句解析の前に実行される点。 このせいで、C のコードは全てのコンテキスト (全ての#includeされるファイル、パス、関連するコンパイラのスイッチ) の情報なしでは字句解析や構文解析ができません。 ミックスインは意味解析の段階で行われ、 字句解析や構文解析には影響しません。 字句・構文解析は依然として意味解析に依存せず実行できます。
- C のプリプロセッサは、
違う文法に見えるものを作れてしまう点:
#define BEGIN { #define END } BEGIN int x = 3; foo(x); END
この子供だましは、ミックスインではできません。 ミックスインする文字列は完全な宣言か、文、 あるいは式でなければなりません。 - C のマクロは、たとえネストしたスコープの中で宣言されていても、 後続のコード中の同名のトークン全てに影響します。 C のマクロはスコープを超えて伝染します。 この問題は、"不衛生なコーディング" と呼ばれています。 ミックスインは通常のスコープ規則に従うので、 衛生的です。
- C のプリプロセッサは、C言語自体と異なった構文を持ち、 異なった意味規則で動作しています。 C のプリプロセッサは技術的に完全に別の言語なのです。 一方、ミックスインは同じ一つの言語です。
- C の const 宣言や C++ のテンプレートは、 プリプロセッサからは認識できません。 ミックスインはテンプレートや const 宣言を使って操作することができます。