振る舞いは通常のメンバ関数であるが、アクセス方法がフィールドのような特殊なメンバが存在します。 これを D 言語ではプロパティと呼びます。 プロパティは、代入演算などの式から直接呼び出すことができるメンバ関数です。
プロパティを使うことによって、従来の言語に多く見られていた Set***() や Get***() または Is***() というような、いわゆるアクセッサメソッドを省略することができます。 クラスのフィールドに外部から直接アクセスされる場合、フィールドの変更と同期しなければならないような処理も外部に委ねなければなりませんでした。 これを解決し、スマートに連帯させる方法がアクセッサメソッドの存在ですが、プロパティはさらにアクセッサメソッドの存在を省略し、外部からは直接フィールドを呼び出しているかのような記述方法でメソッドを呼び出すことができます。
D 言語では、メンバ関数が ( ) 無しで参照された場合は引数の無いメンバ関数であると解釈し、代入演算の代入先にメンバ関数が指定された場合は、引数が 1 つのメンバ関数であると解釈します。 例えば obj . Value = 10 という式で Value という名前のフィールドが存在しない場合、コンパイラは obj . Value (10) と解釈します。 同様に int x = obj . Value という使われ方をした場合、コンパイラは int x = obj . Value() と解釈するのです。
この性質を利用することで SetValue() と GetValue() という形で個別にアクセッサメソッドを宣言しなくても、概念的に Value という名前のプロパティとして統一することができるのです。
import std.stream;
class Point {
int x , y;
int X() {
stdout.printf("Point . GetX %d\n" , x);
return x;
}
void X(int x) {
stdout.printf("Point . SetX %d\n", x);
this.x = x;
}
int Y() {
stdout.printf("Point . GetY %d\n" , y);
return y;
}
void Y(int y) {
stdout.printf("Point . SetY %d\n" , y);
this.y = y;
}
}
int main() {
Point pt = new Point();
pt.X = 10;
pt.Y = 100;
stdout.printf("X=%d,Y=%d\n" , pt.X , pt.Y);
return 0;
}
このプログラムは、X プロパティと Y プロパティを提供する Point クラスを宣言しています。 プロパティの実体はメンバ関数なので、プロパティを提供するクラスは従来のアクセッサメソッドのように値を設定するメンバ関数と値を返すメンバ関数をそれぞれ用意します。 一方で、これらのメンバ関数を呼び出す方法はフィールドにアクセスするかのように、メンバ関数の名前だけで呼び出すことができます。 例えば pt.X = 10 は pt.X(10) と同じであると解釈することができるのです。
もし、読み取り専用プロパティを実現したければ、値を設定するメンバ関数は用意せずに、値を返すメンバ関数だけを用意すればよいでしょう。
D 言語では、デフォルトですべての型と式にプロパティが存在します。 単純型のプロパティでは、その単純型が表すことのできる最大値、最小値、および型が占有するメモリ領域のバイトサイズなどを得ることができます。 C 言語の sizeof() 演算子のような処理を実現するには、sizeof プロパティを使えばよいということになります。
このような型と式のプロパティはオブジェクトのプロパティと異なり実体のメンバ関数が存在するわけではありません。
整数型には、次のようなプロパティが定められています。
| プロパティ | 解説 |
|---|---|
| init | 初期値 (0) |
| sizeof | byte単位でのサイズ |
| size | byte単位でのサイズ(sizeof と同じ) |
| alignof | アラインメントのサイズ |
| max | 最大値 |
| min | 最小値 |
これらのプロパティは int . init という形で型に指定することもできれば int 型の式 ( x ) . init という形で指定することも可能です。
import std.stream;
int main() {
int x = 0;
stdout.printf("init = %d\n" , x.init);
stdout.printf("sizeof = %d\n" , x.sizeof);
stdout.printf("alignof = %d\n" , x.alignof);
stdout.printf("max = %d\n" , x.max);
stdout.printf("min = %d\n" , x.min);
return 0;
}
このプログラムは int 型の変数 x の初期値やバイトサイズなどを表示します。 変数 x に対して .init という形でプロパティを要求していることがわかります。 型と式のプロパティはメンバ関数を呼び出すものではないため、x . init() と記述してもコンパイルエラーとなります。 オブジェクトのプロパティとは異なる性質であることを理解する必要があるでしょう。
同様に、浮動小数点数型のプロパティには次のようなものがあります。
| プロパティ | 解説 |
|---|---|
| init | 初期値 (NaN) |
| sizeof | byte単位でのサイズ |
| size | byte単位でのサイズ(sizeof と同じ) |
| alignof | アラインメントのサイズ |
| max | ∞を除いた最大値 |
| min | 0を除いた最小値 |
| infinity | 無限大 |
| nan | NaN |
| sign | 負なら1, 正なら0 |
| isnan | NaNなら1, でなければ0 |
| isinfinite | ±∞なら1, でなければ0 |
| isnormal | NaNか∞なら1, でなければ0 |
| degits | 精度の10進桁数 |
| epsilon | 最小の増分値 |
| mantissa | 仮数部のビット数 |
| maxExp | 指数の最大値 |
整数型と同様に型や式からこれらのプロパティを通して値を得ることができます。