Smalltalk 在纯消息语言中,有没有一种方法可以在不使用递归或编译器技巧的情况下定义真正的消息?

Smalltalk 在纯消息语言中,有没有一种方法可以在不使用递归或编译器技巧的情况下定义真正的消息?,smalltalk,Smalltalk,Smalltalk具有以下特点:-通过递归(在VisualWorks中)或编译器内联(在Squeak/Pharo中)实现消息。有没有一种方法可以定义这样一种方法而不用其中一种?如果没有,是否有证据可以证明这一点?我提出以下解决方案: BlockContext>>myWhileTrue: aBlock | start | start := thisContext pc. self value ifFalse: [ ^ self ]. aBlock va

Smalltalk具有以下特点:-通过递归(在VisualWorks中)或编译器内联(在Squeak/Pharo中)实现消息。有没有一种方法可以定义这样一种方法而不用其中一种?如果没有,是否有证据可以证明这一点?

我提出以下解决方案:

BlockContext>>myWhileTrue: aBlock 
    | start |
    start := thisContext pc.
    self value ifFalse: [ ^ self ].
    aBlock value.
    thisContext pc: start
上面的代码没有使用递归和编译器技巧,而是在执行堆栈上使用反射。在循环开始之前,该方法将当前程序计数器存储在临时变量中,并在结束时重置它以跳回方法的开始。在一些Smalltalk实现中,这种方法可能会很慢,因为一些Smalltalk方言仅按需具体化堆栈,但在Pharo/Squeak中,这种技巧是非常实用的


注意,上面的代码没有像#whileTrue:的原始实现那样回答最后一个块激活的结果。不过,解决这个问题应该很容易。

您也可以使用异常处理程序使其返回到开头,但如果异常处理代码在某处使用whileTrue:或其他循环构造,则这可能被视为作弊。因此,基本上,问题归结为你是否可以实现一个没有goto或递归的循环,我认为答案是否定的。因此,如果禁止递归,你就只能通过设置方法pc或使用异常等技术拼凑一个goto。

whileTrue:&whileFalse:总是返回nil。 e、 g.如果存在正常的递归定义:

whileTrue: aBlock
    ^self value ifTrue: [self whileTrue: aBlock]
如果self值为false,ifTrue:将返回nil,因此该值应始终为nil。这反映在编译器的优化中。最初的蓝皮书Smalltalk-80 V2定义是

whileTrue: aBlock
    "Evaluate the argument, aBlock, as long as the value
    of the receiver is true. Ordinarily compiled in-line.
    But could also be done in Smalltalk as follows"

    ^self value
        ifTrue:
            [aBlock value.
            self whileTrue: aBlock]
所以把你的名字改成

BlockContext>>myWhileTrue: aBlock 
    | start |
    start := thisContext pc.
    self value ifFalse: [ ^ nil ].
    aBlock value.
    thisContext pc: start
还是

但遗憾的是,这两种方法都会在第二次迭代后的某个时间使VM崩溃,因为thisContext pc不会在下一次迭代中回答pc,而是不管堆栈的顶部是什么:)

但是,以下方法确实有效:

ContextPart methods for controlling
label
    ^{ pc. stackp }

goto: aLabel
    "N.B. we *must* answer label so that the
     top of stack is aLabel as it is when we send label"
    pc := aLabel at: 1.
    self stackp: (aLabel at: 2).
    ^aLabel

BlockContext>>myWhileTrue: aBlock 
    | label |
    label := thisContext label.
    self value ifFalse: [^nil].
    aBlock value.
    thisContext goto: label

BlockClosure>>myWhileTrue: aBlock 
    | label |
    label := thisContext label.
    ^self value ifTrue:
        [aBlock value.
         thisContext goto: label]
只要做:

BlockClousure>>而事实:A锁定

自我价值观:[ A锁定值。
thisContext restart。“在pharo上重启,在VW上重置”]

在这种情况下,恢复上下文基本上等同于GoTo,没有无限递归,没有无限多的语句,也没有恢复上下文的能力,这似乎是不可能的。
ContextPart methods for controlling
label
    ^{ pc. stackp }

goto: aLabel
    "N.B. we *must* answer label so that the
     top of stack is aLabel as it is when we send label"
    pc := aLabel at: 1.
    self stackp: (aLabel at: 2).
    ^aLabel

BlockContext>>myWhileTrue: aBlock 
    | label |
    label := thisContext label.
    self value ifFalse: [^nil].
    aBlock value.
    thisContext goto: label

BlockClosure>>myWhileTrue: aBlock 
    | label |
    label := thisContext label.
    ^self value ifTrue:
        [aBlock value.
         thisContext goto: label]