今日の雑記

生きることでいっぱいいっぱい

D の out と inout

まあ滅多に使わんのですが。ちょっとはまったのでメモ。
Phobos の math ライブラリに、以下のような関数がある。


real modf(real x, inout real y)
ようは浮動小数のあまりを求める関数なのだが、第2引数の「inout real y」ではまった。
以下のような感じにしてたのだが、

BgObj[i].pos[X] = cast(float)modf(cast(real)BgObj[i].pos[X], cast(real)BgObj[i].vel[X]);
んでまあ、

bg.d(n): Error: cast(real)( (*(&( (bg_obj)[(i)]) + 16))[0]) is not an lvalue
ようは「cast(real)BgObj[i].vel[X] は左辺値じゃねえよ!」とコンパイラ様は仰られてる。
正解は、

real tmp = cast(real)BgObj[i].vel[X];
BgObj[i].pos[X] = cast(float)modf(cast(real)BgObj[i].pos[X], tmp);
としなきゃならん。つまり「inout」や「out」指定された引数には cast(hoge) は使えないというか、考えたら至極まっとうな話だった、という落ち。
ドキュメントでは、

  • コンパイラに多くの情報を与えることで、 よりよいエラーチェックやコード生成が 可能になる。
  • (たぶん?) 参照型(&)の宣言が不要になる。
  • out パラメタは、その型のデフォルト初期化子にセットされます。

この辺がそれを匂わせる話かしら?まあ値を返すんだから、受け取る方がその型で無いとメモリ破壊してしまうかも(というか上記の場合確実に)、という訳ですな。
というか D の数学関数はほぼ real 型を使うので、素直にそれに合わせとけ、という話もあるのだが。