如果进程终止,是否可以执行整个ensure块?

时间:2015-09-06 01:32:25

标签: smalltalk pharo

今天我在Pharo中了解到执行:

[v := 1] ensure: [self halt. v := 2]
即使我们在v = 2,窗口(!)放弃了该过程,

也会设置halt

我觉得这个值得商榷。对我来说,#ensure:的语义意味着序列

self halt. v := 2
无论接收器块的情况如何,都必须执行

不管参数块的逻辑。由于#halt的逻辑包括终止过程的事件,我发现它对第二句的顽固评估具有侵扰性。

接下来我尝试了以下内容:

[v := 1] ensure: [1 / 0. v := 2]

当弹出ZeroDivide异常时,我关闭了调试器,但v的值仍为2(与#halt相同。)

最后,我评估了:

[v := 1] ensure: [n := 1 / 0. v := v + n]

并关闭ZeroDivide异常上的调试器。这次v的值为1但我无法评估v + n无法评估的事实。换句话说,错误继续无声。

所以我的问题是。这种行为背后的理性是什么?该过程不应该终止于它将终止于" normal"情况,即没有涉及#ensure:

2 个答案:

答案 0 :(得分:4)

有趣的一个。您的答案似乎取决于BlockClosure>>valueNoContextSwitch调用的#ensure:方法。如果您在那里阅读注释,则表示它创建了BlockClosure>>value(在基元中)的精确副本,并返回该副本的返回值,而不是包含{{1}的原始块的返回值你终止了。因此副本会被执行(显然忽略了复制的halt),即使原始文件没有完成。

我的猜测是,这是为了确保(没有双关语)halt块总是运行,但是有无意识的副作用,忽略了原始块的终止。我同意你的看法,这不仅违反直觉,而且可能也不符合预期。

答案 1 :(得分:1)

我想这是任何(ANSI)标准都没有完全定义的行为,但如果我错了,请纠正我。

其他Smalltalks似乎表现不同。我在Smalltalk / X中尝试过,其中调试器提供3个选项:“继续”(即继续),“中止”(即退出)和“终止”(即终止进程)。我猜“终止”对应于关闭调试器时Squeak的作用。

使用“Abort”和“Terminate”,保证块的其余部分不会执行,“Continue”就是。我想这没关系,你会期待什么。

On Abort和Terminate(它们都是对抗异常处理程序的解除),它不应该尝试重新评估或继续潜在的错误/错误/失败的确保块。

如果要继续或不进行处理程序(调试器基本上是)的选择。如果没有,那么它应该离开ensure块并继续执行可能在调用链中的任何其他保证块。

这与异常处理块的行为一致,如果在其中引发相同的异常,也不会重新评估或继续执行。在ST / X中,异常类中有明确的代码来处理这种情况,所以它绝对是出于目的而不是副作用。

我的猜测是,这在Squeak中是错误的,应该告诉吱吱作响的开发人员。