2012年3月4日日曜日

ActionScript3のSetterがGetterを呼び出す?


「詳説 ActionScript 3.0」には下記の内容が書かれています。
setメソッドは、呼び出されると、それに対応するgetメソッドを常に呼び出し、getメソッドの戻り値を返します。
これによりプログラムでは、新しい値の設定後すぐにその値を使うことができます。
…<中略>…
値を返すsetメソッドの機能は便利に使える一方で、getメソッドに制限を加えています。
特にgetメソッドでは、内部的な変数の値の取得に必要な程度を超える作業は絶対に行うべきではありません。
…<中略>…
setメソッドによるgetメソッドの自動的な呼び出しによって、カウンタの記録の追跡が損なわれることになります。
引用:ActionScript3のsetメソッドの返り値

けれども、上記の引用元でも書かれているように、必ず呼ばれる訳ではなさそう。
自分の環境でも、SetterからGetterは呼ばれていなかった。
それは、OreillyのP79の例のようにSetterの戻り値を何かの値に代入したりして結果を評価しても同じだった。

この辺、FlexSDKのレイヤーとFlashPlayerのレイヤーとどちらに依存しているかはよく分からない。
ちなみに自分の環境は以下(Windows版でも今回書いているすべての結果は同じだった)。
Flex4.1A
Macintosh Flash Player 10.3 Plugin content debugger (Intel-based Macs)
FlashBuilder4.6(体験版)

ここでは、ブレイクポイント設定時にFlashBuilderがおかしな動きをして
あたかもSetterがGetterを呼んでいるかのような挙動に見えてはまったので
そこも含めて確認した結果をメモとして残しておく。

まずは、下記のコードを用意。
ポイントは、以下の2点。
・プロパティpropを用意し、そのGetterでpropCountをインクリメントしてコンソール出力
・execute()でGetterとSetterをそれぞれ呼び出し


まず、ブレイクポイントを設定しない時のexecute()実行時のコンソールは、以下となる。
start
GetterCalled:1
callGetter:0
callSetter
SetterCalled
end
やはり、Setterが呼ばれた時もGetterは呼ばれていない。
(自分の環境では、Oreillyの記述は嘘だったということになる)

ただし、ブレイクポイントを23行目に設定して
1行ずつ28行目まで下記のように変数値を確認しながら動かしてみる。

コンソール出力結果は、下記。Getter呼び出しが増えている(赤字が増えた分)。
GetterCalled:1
start
GetterCalled:2
GetterCalled:3
callGetter:0
GetterCalled:4
callSetter
GetterCalled:5
SetterCalled
GetterCalled:6
end
GetterCalled:7

これ、ちょうどブレイクポイントを設定して変数値を確認した回数だけGetterが呼ばれている。
プロパティpropの値をデバッガ上で見せたくて、FlashBuilderが値を表示するたびにGetterを呼び出しているようだ。
しかも、変数参照ビューをスクロールして画面に表示された瞬間にGetterを呼び出すという手の込みよう。

この時点ではまだGetterは呼び出されていない。
表示領域を少しずつ大きくして・・・propが表示された下記の瞬間に初めてGetterが呼び出される(いないいないばぁ的な)
(ここではいないいないばぁするためにダミーの変数を追加しています)

結論としては、このような変な動きをするケースがあるため、Oreillyにも書いてあるように
Getterの中ではオブジェクト内部で保持する値を更新するような副作用を伴う処理は厳禁ということで。