2.7 Dynamic
2.7 Dynamic
Haxeは静的型システムをもっているが、Dynamic
型を使えば
事実上この型システムを切ることができる。
dynamic値はどの型にも代入できるし、どの型の値もDynamic型に代入できる。
これには次の弱点がある。
- コンパイラは変数への代入、関数呼び出し、その他のconstructsで、 どの型が使われるべきかという型チェックができなくなる。
- 特に静的型システムを使うターゲットにおいて、最適化が使われなくなる。
- よくあるエラー(例えばtypoとか)をコンパイル時に見つけることができなくなる。 これらは実行時エラーとなる。
- Dead Code Eliminationは、
Dynamic
を通して使われると使用されているフィールドを検出できない。
Dynamic
の利用によって実行時にエラーが出る例を考えつくのは簡単だ。
静的ターゲットで次の2行をコンパイルする。
var d:Dynamic = 1; d.foo;
コンパイルしたプログラムをFlash Playerで実行すると
Property foo not found on Number and there is no default value
というエラーが出る。Dynamic
にしなければこのエラーはコンパイル時に検出されたはずだ。
Tribia: Haxe3以前のDynamic Ingerface
Haxe3コンパイラは何かの型を
Dynamic
型と推論することはない。so users must be explicit about it (訳注:訳せない)。以前のバージョンのHaxeは異なる型が混ざった配列、例えば[1, true, "foo"]
をArray<Dynamic>
と推論していた。我々はこの振る舞いは多くの問題を引き起こすことがわかったんで、Haxe3ではやめた。
Dynamic
の使用は最小限にするべきだ。通常は他にもっといい方法がある。しかし、稀にDynamicを使うことが現実的である場合もある。Haxe Reflection APIの一部ではDynamicを使っている。コンパイル時にはわからないようなカスタムデータ構造を扱うような場合には、それが最良の選択になることもある。
Dynamic
behaves in a special way when being unified with a monomorph(訳注:unifiedの訳に困る).
MonomorphはDynamic
になることはない。このため次のような例にみられるような意外な挙動となる。
class Main { static function main() { var jsonData = '[1, 2, 3]'; var json = haxe.Json.parse(jsonData); $type(json); // Unknown<0> for (i in 0...json.length) { // Array access is not allowed on // {+ length : Int } trace(json[0]); } } }
Json.parse
の返り値の型はDynamic
であるが、ローカル変数json
はDynamic
にならず、monomorphのままである。そして、json.length
とフィールドアクセスしたときに、anonymous structureと型推論される。この結果、次のjson[0]
という配列へのアクセスはエラーとなる。これを避けるためには、変数json
を陽にDynamic
として宣言、つまりvar json:Dynamic
とすればよい。
Trivia: 標準ライブラリにおけるDynamic
DynamicはHaxe3以前では標準ライブラリで頻繁に使われていた。Haxeの型システムを改良し続けた結果、Dynamicの使用箇所はHaxe3のリリースまでに少なくなった。
訳注: 雑な訳だなあ