unconditional jump: statement label and goto

在1960 年代进行激烈的讨论,最终 goto 被放弃,这也是被称为“结构化编程”软件革命的一部分。结构化编程在 1970 年代流行起来,1990 年代流行面向对象编程。结构化编程强调从上到下设计(渐进式细化),代码模块化,结构体类型,描述式变量,和不变名称,以及很多注释。结构化编程的开发者可以在 subroutine 中,只使用 顺序,选择,迭代 表达设计良好的命令式算法。不会使用标签,结构化编程依赖嵌套结构的词法边界作为分支控制的目标。

现代程序员熟悉的很多结构化控制流均由 Algol 60 创建。包括

if ... then ... else ...
for ... 
while ...
case(switch)

6.2.1 Structured Alternatives to goto

goto 到 subroutine 结尾引入了 return statement

goto 跳出 loop 引入了 break / exit statement (以及 continue ),有些语言甚至可以从嵌套 subroutine 调用中跳出 exception

Multilevel returns

如果发生 nonlocal goto ,语言就必须提供 repair the run-time stack of subroutine call information, the repair operation 被称为 unwinding

Common Lisp 引入了 catch/throw 机制,Ruby 中也使用,这个机制需要匹配 catch label

Errors and Other Excepitons

多层返回假定调用者知道被调返回什么。但是程序执行异常情况需要被恢复成执行环境。

最直观但是不让人满意的方式是这种

status := my_proc(args);
if status = ok then ...

辅助布尔值可以使用 nonlocal goto 或者多层返回值代替,但是调用方必须显式处理返回值状态。作为结构化替代,很多现代编程语言提供了 exception handling 机制方便处理这种情况,可以恢复意外情况。我们在 9.4 详细讨论 exception handling。开发者通常要提供异常 handler 来从异常中恢复。

多层返回和异常处理有很大的相似性。都是一种从嵌套内层跳到外层的机制。不同之处在于,多层返回内部上下文有所有信息,完成计算,如果正确返回正确值,返回到外层上下文不需要后续处理;异常机制相反,内层上下文不会完成所有工作,执行正常处理,然后抛出异常到外层上下文。

Common Lisp 和 Ruby 都支持,这很少见。大多数语言只支持异常机制;开发者需要自己编写程序处理多层返回。不幸的是,Common Lisp 和 Ruby 使用了 catch/throw 关键字来支持多层返回,而大多数语言使用这两个关键字来支持异常机制。

6.2.2 Continuations

The notion of nonlocal gotos that unwind the stack can be generalized by defining what are known as continuations. In low-level terms, a continuation consists of a code address, a referencing environment that should be established (or restored) when jumping to that address, and a reference to another continuation that represents what to do in the event of a subsequent subroutine return. (The chain of return continuations constitutes a backtrace of the run-time stack.) In higher-level terms, a continuation is an abstraction that captures a context in which execution might continue. Continuations are fundamental to denotational semantics. Scheme 和 Ruby 天然支持,允许开发者定义新的控制流结构。