Factorに入門する(17) top level formsの実行タイミング
収拾付かないFactor入門も17番目。まだまだ全体の景色が見えないので、まとめにははいりませんよ。今日はtop level formsをしっかり理解して帰ってください(オレが)。
top level formsとは、ソースコードのうちdefinitions以外の部分です。どこに書いてあっても、ソースコードすべてがパースされた「後」に実行されます。試してみましょう。
こういうソースファイルを書きます。fooを定義する前にfooを呼ぶコードです。
IN: test USING: io ; foo : foo ( -- ) "test:foo called." print ;
実行すると
P" temp.factor" 4: foo ^ No word named ``foo'' found in current vocabulary search path
パース時のエラーになってます。パースして、コンパイルされて、それから実行されるのですね、たぶん。
ではこういうのはどうでしょうか。
USING: io math prettyprint kernel ; IN: test 3 4 + . : + ( x y -- ) 2drop "test:+ called. dropped values! HAHAHA" ;
こいつを実行すると
7
普通にmathの+が呼ばれます。サーチの順序ではtestが先に入っていますが、パース時点ではまたtest:+が定義されていないからですね。そういうときには、DEFER:で、先にwordの空定義を作っておくことができます。Pascalのforwardみたいなもんですが、FactorのDEFER:では、呼ぶとエラーになるwordがまず定義されます。
まずは、DEFER:で+を宣言して、しかし定義はしないコードを書いてみます。
USING: io math prettyprint kernel ; IN: test DEFER: + 3 4 + .
実行結果。
Calling a deferred word before it has been defined
DEFER:した+がまだ定義されていない、と怒られました。
+の呼び出しの「後」に、vocaburary "test"の+を定義して、実行してみましょう。
USING: io math prettyprint kernel ; IN: test DEFER: + 3 4 + . : + ( x y -- str ) 2drop "test:+ called. dropped the values! HAHAHA" ;
"test:+ called. dropped the values! HAHAHA"
ということで、test内で+を定義したのより後にtop level formが実行されていることが確認できました。
ドキュメントには、前回疑問に思った"ソースファイル中でinがとれない"ということについても書いてありました。
Top-level forms do not have access to the in and use variables that were set at parse time, nor do they run inside with-compilation-unit; so meta-programming might require extra work in a top-level form compared with a parsing word.
さらに、変数スコープもtop-levelではダイナミックなあたらしいものが生成されるそうで、実行後にそのスコープはなくなってしまうそうな。このあたりの詳細は、スコープのところをやるときにつっこんでみることにします。