3

I'm not quite sure how variable scope works in Io. The docs say it has closures, but I don't seem to be able to see idx from within the next and prev methods. Parent visibility is the key premise of closures, so how can they work?

List iterator := method(
    idx := 0

    itr := Object clone
    itr next := method(
        idx = idx + 1
        return self at(idx)
    )

    itr prev := method(
        idx = idx - 1
        return self at(idx)
    ) 

    return itr
)

How should this be achieved?

4

1 回答 1

7

所以你从根本上误解了方法和块是如何工作的,但这没关系。让我们回顾一下基础知识:

  1. 方法是在您按名称调用它们时激活的块,其范围设置为 nil。当我们谈论范围时。
  2. 块的范围设置为创建它们的上下文。

context 表示一个本地对象,基本上是一个堆栈帧。范围意味着当块/方法被调用时谁将成为块激活的“发送者”。您可以通过call sender方法或块的上下文中的对象访问它。

现在,让我们看看你的代码。它几乎是完美的,只缺少一件事,而且不明显。

由于方法具有动态范围,因此它们的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()在功能上是等效的。

方法不是闭包,块是。块只是一个范围为非零的方法,它们是同一个对象。

于 2013-11-12T21:53:46.903 回答