どこでもローカル変数を定義できる自由は、 プログラミング・スタイルを劇的に変える可能性を秘めています。 特に、
中間ストレージにリターン・スタックを使用する必要がなくなります。 さらに、 すべてのスタック操作(実行時に決定される引数を持つ PICK
や ROLL
を除く)を排除できます。 スタック項目の順序が間違っている場合は、 すべてのスタック項目のローカル変数定義を記述し、
その次に、 あなたが必要とする順序で項目を書き込むだけです。
これは少し突飛なように思えますし、 スタック操作を排除することが意識的なプログラミング目標になる可能性は低いです。 それでも、
ローカル変数を積極的に使用すれば、 スタック操作の数は大幅に減少します(例: max
(see Gforth locals) を
max
の従来の実装と比較してみましょう)。
これは、 ローカル変数の潜在的な利点の 1 つ、 つまり Forth プログラムを読みやすくすることを示しています。 もちろん、 この利点は、 プログラマがワードを長ったらしく書くための自由度を追加する訳ではなく、 ファクタリング(因数分解)の原則を尊重し続けた場合にのみ実現されます。
TO
の使用は可能な限り避けるべきです。 TO
がない場合、 すべてのvalueフレーバーのローカル変数には 1
つの代入しかなく、 関数型言語の多くの利点が Forth に当てはまります。 つまり、 プログラムの分析・最適化・読み取りが容易になります。
ローカル変数が何を表すかは定義から明らかであり、 後で別のものに変わることはありません。
たとえば、 TO
を使用したローカル変数定義は以下のようになります:
: strcmp {: addr1 u1 addr2 u2 -- n :} u1 u2 min 0 ?do addr1 c@ addr2 c@ - ?dup-if unloop exit then addr1 char+ TO addr1 addr2 char+ TO addr2 loop u1 u2 - ;
ここで、 TO
は、 ループの反復ごとに addr1
と addr2
を更新するために使用されます。
strcmp
は、TO
の使用による可読性の問題の典型的な例です。 strcmp
を読み始めると、
addr1
が文字列の先頭を指していると考えるでしょう。 ループの終わり近くになって初めて、 それが何か別のものであることがわかります。
これは、 現在の反復に適切な値で初期化される 2 つのローカル変数をループの開始時に定義することで回避できます。
: strcmp {: addr1 u1 addr2 u2 -- n :} addr1 addr2 u1 u2 min 0 ?do {: s1 s2 :} s1 c@ s2 c@ - ?dup-if unloop exit then s1 char+ s2 char+ loop 2drop u1 u2 - ;
ここで、 s1
がループの反復ごとに異なる値を持つことは最初から明らかです。