こちら のサイトでVoldemort Typesとかいう衝撃的な名前のものを見たのでしっかり読み込んでみた。
前提
まずインデックスの2乗が得られる構造体があるとする。
module voldemort;
struct TomRiddle
{
size_t opIndex(size_t n)
{
return n*n;
}
}
そしてそれを返す関数がある。
TomRiddle generator()
{
return TomRiddle();
}
このモジュールを使ってこのようなコードを書く。
import std.stdio;
import voldemort;
void main()
{
TomRiddle square = generator();
foreach(i;0 .. 5)
{
writeln(square[i]);
}
}
実行するとこうなる。
0
1
4
9
16
ユーザーコードにTomRiddle
が出てきているので、カプセル化に失敗している。
たとえばこの型をVoldemort
に変えると当然動かなくなる。
module voldemort;
struct Voldemort
{
size_t opIndex(size_t n)
{
return n*n;
}
}
Voldemort generator()
{
return Voldemort();
}
source/app.d(6,15): Error: undefined identifier 'TomRiddle'
Voldemort Types
ここで構造体Voldemort
の定義をgenerator
の中に入れる。
module voldemort;
auto generator()
{
struct Voldemort
{
size_t opIndex(size_t n)
{
return n*n;
}
}
return Voldemort();
}
するとVoldemort
はVoldemort Typeになる。
Voldemort Typeは関数の外でその名前を呼ぶことができない。
以下のようにちゃんと正しい名前で呼んであげてもエラーが出る。
import std.stdio;
import voldemort;
void main()
{
Voldemort square = generator();
foreach(i;0 .. 5)
{
writeln(square[i]);
}
}
source/app.d(6,15): Error: undefined identifier 'Voldemort', did you mean import 'voldemort'?
Voldemort Typeは型推論を介してしか渡すことができなくなる。 つまりこのようなコードになる。
import std.stdio;
import voldemort;
void main()
{
auto square = generator();
foreach(i;0 .. 5)
{
writeln(square[i]);
}
}
0
1
4
9
16
こんな感じで新しいインスタンスを生成しようとしてみる。
auto square = generator();
typeof(square) square2;
しかしコンパイラは関数のスコープの外でVoldemort
がインスタンス化されるのを許さない。
source/app.d(7,20): Error: cannot access frame pointer of voldemort.generator.Voldemort
まとめ
Voldemort Typeは型をカプセル化する方法であり、Andrei Alexandrescuによって命名された。 Rangeとかに使うと便利らしい。 これには実行可能ファイルのサイズが大きくなる欠点があるらしく、それを防ぐためにHorcrux(分霊箱) Methodというのがあるようだが、ちょっとそれはまた今度。
追記: オブジェクトファイルが大きくなる問題はDMD 2.077.0で改善されたらしい。