鍋あり谷あり

テーマを決めずに適当に書いています。

AS2の型検査

コンパイル時の型検査の話だったんですね。たしかにそう書いてあります。とほほ。>id:soutaro
それと。タイトルが「MTASCの型検査」だったのがよくありませんでした。AS2 の型検査と書くべきでした。
id:soutaro 様の興味とは離れていくと思いますが、実行時の型の話を中心にもうちょっと AS2*1の型の話を書いてみます。

で。文体が変わり。

実は私も Macromediaコンパイラよりも MTASC の方が型検査が厳しいのかな。と思っていた。Macromediaコンパイラが手元にないのでその辺りはわからないのだが、いろいろ試していると、どうも MTASC でもほとんど型検査をしていなさそうなので、同程度だと思われる。これ以下の実装は想像できないからだ。

それとは別に。
AS2 の型は、ちょっと意外な実装になっている。少なくとも、私には意外であった。

var a:Number=0; // これは正しいに決まっている。
var b:Number=true; // type error Boolean should be Number。暗黙の変換は行われない
var c:Number=["foo"][0]; // 配列経由だと何を入れられても気づかない
var d:Number=new Object(0); // type error Object should be Number。
var e:Number=function():Object{  return 0;  }() // type error Object should be Number。

上記の結果だけを見ると、なんとなくああそうかという気になるかもしれないが。

var d=new Object(0);
var e=function():Object{  return 0;  }()
var o:Object = 0;
var f = o;
var g:Object = Object(0);
var h:Object = 0;

を実行すると、

typeof(d) == "object"
typeof(e) == "number"
typeof(f) == "number"
typeof(g) == "object"
typeof(h) == "number"

となる。e への代入はコンパイル時にはエラーになるが、実行時には正しい型が入る。c への代入はコンパイルは通るものの実行時には不正な型が入る。

この結果から、変数の型指定はコンパイルエラーを出す以外には何の役にも立っていなさそうだとわかる。と思う。しかも、チェックは非常にいい加減。

d, g は object で e, f, h は number だが、両者の間には実際違いがある。
d.foo="bar" などとすると、d, g は実際に d.foo, g.foo には "bar" を格納することができるが、e.foo="bar" などとしても、e.foo は undefined のままである*2
しかし、d, g は純粋な Object 型かというとそうでもなく、d+1, g+=2 は普通に計算できる*3

ちなみに。

var g:Object = Object(0);
var h:Object = 0;
var i:Number = [Object(0)][0]
var j:Number = 0;
var p=false
var q=Object(false)

を実行すると、

!g==false,  (0==g)==true
!h==true,   (0==h)==true
!i==false,  (0==i)==true
!j==true,   (0==j)==true
!p==true,
!q==false,

となる。
この例も、変数につけられた型が役に立っていないことを示している。
! 演算子と 「0==」 が一致しないのはちょっと意外だし、!Object(false) が false なのも意外である。

難しい。

*1:昨日は ActionScript と書いたが、ActionScript1.0 にはなかった機能なので、ActionScript2.0 と書くべきだったと思う。略して AS2

*2:にもかからわず、e.foo="bar" は、例外を返したりはしない。まずい仕様だと思う。

*3:しかし、d*2 や g-=1 はコンパイルエラー。足し算しかできないのか。