素朴な疑問にひっかかった。if とか else もメソッドで、引数にメッセージをとるけど、何でこの引数は評価されずに渡されるんだろう。ちょっと解りにくいから実際にコードを書いてみる。
if (Nil) then ( "not print" print ) else ( "print" print )
この場合もちろん not print は出力されないし、それが願う動作。しかしながら "not print" print
も引数だから、メソッドに渡される前に評価されて not print と出力されるんじゃないかと悩んだ。というか正確に言えば if をユーザから定義するときに評価されてしまってハマった。以下にハマったコードを示す
myif := method(test, ifObj := Object clone ifObj test := test ifObj do ( mythen := method(msg, if (test, sender doMessage(thisMessage argAt(0))) self ) myelse := method(msg, if (test isNil, sender doMessage(thisMessage argAt(0))) self ) ) ) myif (Nil) mythen ( "nil" print ) myelse ( "aaa" print )
これは予想に反して nilnilaaa と出力される。引数が渡される前に評価されしまっているからだ。リファレンス見ててもよくわからないので、適当に書き直していたらできた。書き直した結果を書いてみる。
myif := method(test, ifObj := Object clone ifObj test := test ifObj do ( mythen := method( if (test, sender doMessage(thisMessage argAt(0))) self ) myelse := method( if (test isNil, sender doMessage(thisMessage argAt(0))) self ) ) )
何が変わったかっていうと method の仮引数を書かないようにしただけ。仮引数を書くと評価されてしまうらしい。微妙な罠。プログラミングガイドに明記してもいいじゃん! とはいえこれを踏まえてから読み直すと The thisMessage slot that is preset (see next section) in locals can be used to access the unevaluated argument messages.
と書かれていてといっても原文は引用しただけで日本語訳から探した。 (強調はされていない) 頭がよければ thisMessage スロットには未評価なメッセージが入っていて、仮引数を書かなくても呼び出せる。もしかして仮引数を書かなければメッセージは評価されないんじゃないか、なんて推論できる (苦しい) かもしれないけど、俺には無理!