インスタンス変数へのアクセス

PowerMops 6.1から実装された機能である、:modifs_in , ;end_modifsの説明をします。

Mopsには、イベントハンドラーなど、オブジェクト毎に同じメソッドの動作を微妙に変えたいことがある場合のために、そのために定義されたワードのxtをオブジェクトに格納しておいて、必要に応じてEXECUTEで実行するという機構が備わっています。例えば、ViewクラスのSetDraw:やSetClick:などがxtを登録する代表的なメソッドで、これで登録されたワードは、そのViewオブジェクトにDraw:ないしClick:メッセージが送られたときに、自動的に実行されます。そして、これら後者のメソッドは対応するイベントが起ったときに実行されるようになっているわけです。

ここで登録されるワードは、普通のコロン定義で定義されるワードです。このワードの定義の中で、オブジェクトにアクセスする方法としては、これまでは、^BASEというワードを用いて、そのオブジェクトのベースアドレスを取ることによって実行する他ありませんでした。ですから、このワードから個々のインスタンス変数にアクセスしたいときには、元のクラス定義を書き換えて、そのインスタンス変数に適切にアクセスするメソッドを追加するなどして、本体のオブジェクトのメソッド経由で行わなければなりません。本筋としてはそれが正しいのですが、この手間を少しだけ省くための簡便法が:modifs_in , ;end_modifsです。

使用法は、
:modifs_in  AClass
...
;end_modifs
という形で、...の部分は、クラス/メソッド定義の中と同じように、クラスAClassのプライベートなインスタンス変数にメッセージを送るコードをコンパイルすることができます。

単純な例でみましょう。
:class testview super{ view }
rect drawrect
string charstring
:m putrect: put: drawrect  ;m
:m putstr: put: charstring  ;m
;class

:Modifs_in testview

: drawRectangle   draw: drawrect  ;
: typetext   20 20 gotoXY get: charstring type  ;
: clearrectangle   clear: drawrect   ;

;end_modifs

testview myview

10 10 150 30 putrect: myview
" This is for test. OK?" putstr: myview

' typetext setdraw: myview

window+ ww
rect framerect
50 50 350 450 put: framerect

上のコードをenterした後で、
framerect " test" docwind true false myview new: ww
を実行します。すると、次のようなウィンドウがでます。


次に、
' drawrectangle setdraw: myview
update: ww
と実行すると、次のように文字に枠がつきます。


そして、また
' clearrectangle setdraw: myview
update: ww
と実行すれば、全部消されます。


ポイントが分かりにくいコードですみませんが、重要なのは、Setdraw:を通じた実行ワードの変更によって、オブジェクト毎に動作を違えることも、実行中に同じオブジェクトの動作を変えることもできるという点です。そして、その動作内容を定めるワード定義内からそのオブジェクトのプライベートデータであるインスタンス変数に直接アクセスできるようにするのが、:modifs_inと;end_modifsなわけです。

注意:上のコードの動作は、MacOS 9上では違ったものになるかも知れません(試してませんが)。OS Xでは描画の仕組みが変わったせいで、draw:を呼ぶイベントが、OS 9よりも頻度が減ったような気がします。

なお、ちょっと裏話になりますが、実は、この:modifs_in , ;end_modifsで囲われた部分は、まさに":modifs_in"の後に宣言されたクラス(上の例だとtestviewクラス)の定義の中と同じ状態になり、SELFにメッセージを送ることもでき、極端な話、メソッドとか新しいインスタンス変数とかを追加することまでできてしまいます。ですが、これは、クラスそのものを変形してしまうということで、この変形の前に生成されたオブジェクトと、後に生成されたオブジェクトとが、同じクラスであるにもかかわらず、構造が異なるものとなってしまいます。これは危険(最悪、実行コードがクラッシュする)な行為なので、やるべきではありません。単純に、インスタンス変数に直接アクセスできるための方法として利用すべきでしょう。こういう事ができるのも、Mops/Forthの「何でもできる」パワフルさの現れではあるんですけれども。


関連項目:






最終更新:2019年05月31日 16:30