Next: , Previous: , Up: Defining Words   [Contents][Index]


6.10.11 Deferred Words

定義ワード defer (訳注: (期限を定めない)延期)を使用すると、 その振る舞いを定義せずに名前でワードを定義できます。 その振る舞いの定義は延期(defer)されます。 これが役立つ 2 つの状況を以下に示します:

以下の例では、 foo は常に greet の「Good breakfast」を出力するバージョンを呼び出し、 bar は常にgreet の「Hello」を出力するバージョンを呼び出します。 ソースコードを並べ替えて再コンパイルすることなく、 foo で新しいバージョンを使用できるようにする方法はありません。

: greet ." Good morning" ;
: foo ... greet ... ;
: greet ." Hello" ;
: bar ... greet ... ;

この問題は、 greetdefer された ワードとして定義することで解決できます。 defer された ワードの振る舞いは、 IS を使用して以前に定義されたワードの xt と関連付けることによって、 いつでも定義および再定義できます。 上記の例は以下のようになります:

Defer greet ( -- )
: foo ... greet ... ;
: bar ... greet ... ;
: greet1 ( -- ) ." Good morning" ;
: greet2 ( -- ) ." Hello" ;
' greet2 IS greet  \ make greet behave like greet2

プログラミング・スタイル・メモ: すべての defer された ワードに対してスタック・コメントを記述し、 かつ、 そのスタック効果に一致する XT のみを defer されたワードに入れる必要があります。 そうしないと、 defer されたワードを使用するのは非常に困難です。

defer された ワードを使用すると、 User-defined Defining Words の統計収集の例(statistics-gathering example)を改善できます。 アプリケーションのソース・コードを編集してすべての :my: に変更するのではなく、 以下のようにします:

: real: : ;     \ retain access to the original
defer :         \ redefine as a deferred word
' my: IS :      \ use special version of :
\
\ load application here
\
' real: IS :    \ go back to the original

注意すべき点の 1 つは、 IS には特別なコンパイル機能(compilation semantics)があり、 (TO のように)コンパイル時に名前をパースするということです:

: set-greet ( xt -- )
  IS greet ;

' greet1 set-greet

IS が適合しない状況では、 代わりに defer! を使用してください。

defer された ワードは、 xt から実行機能(execution semantics)のみを継承できます(xt が表現できるのはそれだけであるためです – これについての詳しい説明は see Tokens for Words 参照)。 デフォルトでは、この実行機能(execution semantics)から派生したデフォルトのインタプリタ機能(interpretation semantics)とコンパイル機能(compilation semantics)を持ちます。 ただし、 defer された ワードのインタプリタ機能とコンパイル機能は、 通常の方法で変更できます。

: bar .... ; immediate
Defer fred immediate
Defer jim

' bar IS jim  \ jim has default semantics
' bar IS fred \ fred is immediate
Defer ( "name" –  ) core-ext “Defer”

defer された ワード name を定義します。 その実行機能(execution semantics)は defer! または is で設定できます(最初に name を実行する前に設定する必要があります)。

defer! ( xt xt-deferred –  ) core-ext “defer-store”

xt (xt-deferred) で表される defer された ワードに実行のための xt を設定します。

IS ( xt "name" –  ) core-ext “IS”

defer された ワード name に実行のための xt を設定します。

defer@ ( xt-deferred – xt  ) core-ext “new-defer-fetch”

xt は、 defer された ワード xt-deferred に現在関連付けられているワードを表します。

action-of ( interpretation "name" – xt; compilation "name" – ; run-time – xt  ) core-ext “action-of”

Xt は、 現在 name に割り当てられている XT です。

Forth-94 では、 これら Forth-2012 のワードの定義は、compat/defer.fs で提供されます。 さらに、 Gforth は以下を提供します:

defers ( compilation "name" – ; run-time ... – ...  ) gforth-0.2 “defers”

defer された ワード name の現在の内容を現在の定義にコンパイルします。 つまり、 これにより、 name が defer されなかったかのように静的結び付け(static binding)が生成されます。

wrap-xt ( xt1 xt2 xt: xt3 – ...  ) gforth-1.0 “wrap-xt”

defer された ワード xt2 の現在の xt-current をどこかに退避して xt1 に設定した上で、 xt3 を実行し、 xt3 実行後、 退避した xt-current を defer されたワード xt2 に戻します(訳注: xt3 の内部のどこかで defer されたワード xt2 を使っているとして、 xt2 の実行機能を一時的に xt1 に設定してから xt3 を実行し、 実行後に xt2 の実行機能を元に戻しておく。 元に戻すのは try ... restore ... endtry で囲まれた部分なので xt3 実行中にエラーがあっても確実に復旧される。 詳しくはソースコード見て下さい。 なお、 xt: は xt3 を deferフレーバーに設定する)

preserve ( "name" –  ) gforth-1.0 “preserve”

指定の defer された ワード name で、 現在設定されている実行機能 xt を、 その場で isdefer! したかのようなコードに変換します(訳注: 上記例より、 ’ greet2 is greet : preserve-greet2 preserve greet ; → greet1 is greet ok → greet Good morning ok → preserve-greet2 ok → greet Hello ok ; see preserve-greet2 → : preserve-greet2 ‘greet2 ‘greet ! ; ok)


Next: Forward, Previous: User-defined Defining Words, Up: Defining Words   [Contents][Index]