つまり、メソッドとブロックがどのように機能するかを根本的に誤解していますが、それは問題ありません。基本を見てみましょう:
- メソッドは、名前で呼び出すとアクティブになり、スコープが nil に設定されているブロックです。スコープについて話すとき。
- ブロックのスコープは、ブロックが作成されたコンテキストに設定されています。
context は locals オブジェクト、基本的にはスタック フレームを意味します。スコープとは、ブロック/メソッドが呼び出されたときに、誰がブロック アクティベーションの「送信者」になるかを意味します。call sender
メソッドまたはブロックのコンテキスト内のオブジェクトによってこれにアクセスできます。
それでは、コードを見てみましょう。ほぼ完璧です。欠けているのは 1 つだけで、明らかではありません。
メソッドには動的スコープがあるため、そのscope
メッセージは nil を返します。これは、そのメッセージを受信したオブジェクトが送信コンテキストとして渡されるべきであることをエバリュエーターに示します。私たちはその動作を望んでいません。特定のスコープ、特にiter
定義したメソッドのローカルをキャプチャしたいのです。修正された例を見てみましょう。
List iterator := method(
idx := 0
itr := Object clone
itr next := method(
idx = idx + 1
at(idx)
) setScope(thisContext)
itr prev := method(
idx = idx - 1
at(idx)
) setScope(thisContext)
itr
)
本文を簡素化しましたが、機能面で変更はありません (メッセージ送信数が少ないことを除けば)。重要なのは、/setScope
への割り当ての前にメソッドに渡される呼び出しです。これを次のように書き直すこともできました。next
prev
iter prev := block(
idx = idx - 1
at(idx)
) setIsActivatable(true)
しかし、ブロックはデフォルトではアクティブ化できないため、ブロックをアクティブ化する必要がありました。上記のコードと修正されたitr prev
使用法method()
は、機能的に同等です。
メソッドはクロージャではなく、ブロックです。ブロックは単にスコープが非 nil のメソッドであり、同じオブジェクトです。