注:机翻,未校。
Go To Statement Considered Harmful
goto 语句有害论
Edsger W. Dijkstra
埃德斯加·W·迪杰斯特拉
Reprinted from Communications of the ACM, Vol. 11, No. 3, March 1968, pp. 147 - 148. Copyright © 1968, Association for Computing Machinery, Inc.
转载自《美国计算机协会通讯》1968年3月第11卷第3期,第147 - 148页。版权所有©1968,美国计算机协会。
This is a digitized copy derived from an ACM copyrighted work. It is not guaranteed to be an accurate copy of the author’s original work.
这是一份源自美国计算机协会版权作品的数字化副本,不能保证其与作者原始作品完全一致。
Key Words and Phrases:
关键词和短语:
go to 语句、跳转指令、分支指令、条件子句、选择子句、重复子句、程序可读性、程序顺序控制
CR Categories:
CR 分类:
4.22、6.23、5.24
Editor:
编者按:
For a number of years I have been familiar with the observation that the quality of programmers is a decreasing function of the density of go to statements in the programs they produce. More recently I discovered why the use of the go to statement has such disastrous effects, and I became convinced that the go to statement should be abolished from all “higher level” programming languages (i.e. everything except, perhaps, plain machine code). At that time I did not attach too much importance to this discovery; I now submit my considerations for publication because in very recent discussions in which the subject turned up, I have been urged to do so.
多年来,我一直留意到这样一种现象:程序员所编写程序中 goto 语句的密集程度越高,其编程水平就越低。最近我弄清楚了 goto 语句的使用为何会产生如此糟糕的影响,并且坚信 goto 语句应该从所有“高级”编程语言(或许,这里指的是除了纯机器码之外的所有语言)中剔除。当时我并没有太重视这一发现;现在我将这些思考提交发表,是因为在最近相关主题的讨论中,有人极力劝我这么做。
My first remark is that, although the programmer’s activity ends when he has constructed a correct program, the process taking place under control of his program is the true subject matter of his activity, for it is this process that has to accomplish the desired effect; it is this process that in its dynamic behavior has to satisfy the desired specifications. Yet, once the program has been made, the “making” of the corresponding process is delegated to the machine.
我的第一个观点是,尽管程序员在构建出正确的程序后,其编程活动就结束了,但程序所控制的进程才是其编程活动真正的核心内容。因为正是这个进程需要实现预期效果,正是这个进程在动态运行中需要满足预期的规范。然而,一旦程序编写完成,相应进程的“运行”就交给了机器。
My second remark is that our intellectual powers are rather geared to master static relations and that our powers to visualize processes evolving in time are relatively poorly developed. For that reason we should do our utmost to shorten the conceptual gap between the static program and the dynamic process, to make the correspondence between the program (spread out in text space) and the process (spread out in time) as trivial as possible.
我的第二个观点是,我们的智力更倾向于掌握静态关系,而我们对随时间演变的进程进行可视化想象的能力则相对较弱。因此,我们应该竭尽全力缩小静态程序与动态进程之间的概念差距,使程序(在文本空间中展开)和进程(在时间中展开)之间的对应关系尽可能简单明了。
Let us now consider how we can characterize the progress of a process. If the program text is a pure concatenation of assignment statements it is sufficient to point in the program text to a point between two successive action descriptions. (In the absence of go to statements I can permit myself the syntactic ambiguity in the last three words of the previous sentence: if we parse them as “successive (action descriptions)” we mean successive in text space; if we parse as “(successive action) descriptions” we mean successive in time.) Let us call such a pointer to a suitable place in the text a “textual index.”
现在让我们思考如何描述一个进程的进展。如果程序文本仅仅是赋值语句的简单拼接,那么在程序文本中指出两个连续动作描述之间的某个点就足以描述进程的进展。(在没有 goto 语句的情况下,我可以允许上一句话最后三个词存在句法歧义:如果我们将其解析为“连续的(动作描述)” ,指的是在文本空间中的连续;如果解析为“(连续动作)的描述” ,指的是在时间上的连续。)我们把指向文本中合适位置的这种指针称为“文本索引”。
When we include conditional clauses (if B then A ), alternative clauses (if B then
A
1
A1
A1 else
(
A
2
)
(A2)
(A2) ), choice clauses as introduced by C. A. R.Hoare (case[i] of
(
A
1
,
A
2
,
⋯
,
A
n
)
)
(A 1, A 2, \cdots, A n))
(A1,A2,⋯,An)) ,or conditional expressions as introduced by J. McCarthy (
(
B
1
−
>
E
1
(B 1->E 1
(B1−>E1 ,
B
2
→
E
2
,
⋯
,
B
n
→
E
n
)
B 2 \to E 2, \cdots, B n \to E n)
B2→E2,⋯,Bn→En) , the fact remains that the progress of the process remains characterized by a single textual index.
当我们在程序中加入条件子句(if B then A)、选择子句(if B then
A
1
A1
A1 else
(
A
2
)
(A2)
(A2) )、C. A. R. 霍尔提出的选择子句(case[i] of
(
A
1
,
A
2
,
⋯
,
A
n
)
(A 1, A 2, \cdots, A n)
(A1,A2,⋯,An) ),或者J. 麦卡锡提出的条件表达式(
(
B
1
−
>
E
1
(B 1->E 1
(B1−>E1 ,
B
2
→
E
2
,
⋯
,
B
n
→
E
n
)
B 2 \to E 2, \cdots, B n \to E n)
B2→E2,⋯,Bn→En) 时,进程的进展仍然可以用单一的文本索引来描述。
As soon as we include in our language procedures we must admit that a single textual index is no longer sufficient. In the case that a textual index points to the interior of a procedure body the dynamic progress is only characterized when we also give to which call of the procedure we refer. With the inclusion of procedures we can characterize the progress of the process via a sequence of textual indices, the length of this sequence being equal to the dynamic depth of procedure calling.
一旦我们在编程语言中引入过程(函数),就必须承认单一的文本索引不再够用。当文本索引指向过程体内部时,只有同时指明所引用的是该过程的哪一次调用,才能描述动态进展。引入过程后,我们可以通过一系列文本索引来描述进程的进展,这个序列的长度等于过程调用的动态深度。
Let us now consider repetition clauses (like, while B repeat A or repeat A until B ). Logically speaking, such clauses are now superfluous, because we can express repetition with the aid of recursive procedures. For reasons of realism I don’t wish to exclude them: on the one hand, repetition clauses can be implemented quite comfortably with present day finite equipment; on the other hand, the reasoning pattern known as “induction” makes us well equipped to retain our intellectual grasp on the processes generated by repetition clauses. With the inclusion of the repetition clauses textual indices are no longer sufficient to describe the dynamic progress of the process. With each entry into a repetition clause, however, we can associate a so-called “dynamic index,” inexorably counting the ordinal number of the corresponding current repetition. As repetition clauses (just as procedure calls) may be applied nestedly, we find that now the progress of the process can always be uniquely characterized by a (mixed) sequence of textual and/or dynamic indices.
现在来考虑重复子句(比如while B repeat A 或 repeat A until B )。从逻辑上讲,这类子句现在是多余的,因为我们可以借助递归过程来表达重复操作。但出于实际考虑,我并不想排除它们:一方面,重复子句在如今的有限设备上很容易实现;另一方面,“归纳”这种推理模式让我们有能力理解重复子句所产生的进程。加入重复子句后,文本索引不再足以描述进程的动态进展。不过,每次进入重复子句时,我们可以关联一个所谓的“动态索引”,它会不断记录当前重复的序数。由于重复子句(和过程调用一样)可以嵌套使用,我们发现现在进程的进展总能通过文本索引和/或动态索引组成的(混合)序列唯一地描述出来。
The main point is that the values of these indices are outside programmer’s control; they are generated (either by the write-up of his program or by the dynamic evolution of the process) whether he wishes or not. They provide independent coordinates in which to describe the progress of the process.
关键在于,这些索引的值不受程序员控制;无论程序员是否愿意,它们都会(由程序编写或进程的动态演变)生成。它们为描述进程的进展提供了独立的坐标。
Why do we need such independent coordinates? The reason is - and this seems to be inherent to sequential processes - that we can interpret the value of a variable only with respect to the progress of the process. If we wish to count the number, n say, of people in an initially empty room, we can achieve this by increasing n by one whenever we see someone entering the room. In the in - between moment that we have observed someone entering the room but have not yet performed the subsequent increase of n , its value equals the number of people in the room minus one!
为什么我们需要这样的独立坐标呢?原因在于——这似乎是顺序进程所固有的——我们只能根据进程的进展来解释变量的值。假设我们想统计一个最初空房间里的人数
n
n
n ,每当看到有人进入房间,就把
n
n
n 加1来实现统计。在我们看到有人进入房间但还没来得及给
n
n
n 加1的这个间隙,
n
n
n 的值就等于房间里实际人数减1!
The unbridled use of the go to statement has an immediate consequence that it becomes terribly hard to find a meaningful set of coordinates in which to describe the process progress. Usually, people take into account as well the values of some well chosen variables, but this is out of the question because it is relative to the progress that the meaning of these values is to be understood! With the go to statement one can, of course, still describe the progress uniquely by a counter counting the number of actions performed since program start (viz. a kind of normalized clock). The difficulty is that such a coordinate, although unique, is utterly unhelpful. In such a coordinate system it becomes an extremely complicated affair to define all those points of progress where, say, n equals the number of persons in the room minus one!
不加节制地使用 goto 语句会直接导致很难找到一套有意义的坐标来描述进程的进展。通常,人们也会考虑精心挑选的一些变量的值,但这是不可行的,因为这些值的含义要根据进程的进展来理解!当然,使用 goto 语句时,也可以通过一个计数器记录程序启动后执行的动作数量(即一种标准化时钟)来唯一地描述进程进展。问题在于,这样的坐标虽然是唯一的,但毫无用处。在这样的坐标系中,要定义所有像
n
n
n 等于房间里人数减1这样的进程进展点,会变得极其复杂!
The go to statement as it stands is just too primitive; it is too much an invitation to make a mess of one’s program. One can regard and appreciate the clauses considered as bridling its use. I do not claim that the clauses mentioned are exhaustive in the sense that they will satisfy all needs, but whatever clauses are suggested (e.g. abortion clauses) they should satisfy the requirement that a programmer - independent coordinate system can be maintained to describe the process in a helpful and manageable way.
现有的 goto 语句太过原始;它太容易让程序变得混乱不堪。人们可以把前面提到的那些子句看作是对 goto 语句使用的限制,并且认可这种做法。我并不是说所提到的这些子句能满足所有需求,但无论提出什么子句(比如终止子句),它们都应该满足这样一个要求:能够维持一个独立于程序员的坐标系,以便有效地、易于管理地描述进程。
It is hard to end this with a fair acknowledgment. Am I to judge by whom my thinking has been influenced? It is fairly obvious that I am not uninfluenced by Peter Landin and Christopher Strachey. Finally I should like to record (as I remember it quite distinctly) how Heinz Zemanek at the pre - ALGOL meeting in early 1959 in Copenhagen quite explicitly expressed his doubts whether the go to statement should be treated on equal syntactic footing with the assignment statement. To a modest extent I blame myself for not having then drawn the consequences of his remark.
很难在结尾时恰如其分地致谢。该如何判断谁对我的思考产生了影响呢?很明显,彼得·兰丁和克里斯托弗·斯特雷奇对我有一定影响。最后,我清楚地记得,1959年初在哥本哈根举行的ALGOL语言前期会议上,海因茨·泽曼内克明确表达了他对 goto 语句是否应与赋值语句在句法上同等对待的质疑。在一定程度上,我怪自己当时没有从他的话中得出应有的结论。
The remark about the undesirability of the go to statement is far from new. I remember having read the explicit recommendation to restrict the use of the go to statement to alarm exits, but I have not been able to trace it; presumably, it has been made by C. A. R. Hoare. In [1, Sec. 3.2.1.] Wirth and Hoare together make a remark in the same direction in motivating the case construction: “Like the conditional, it mirrors the dynamic structure of a program more clearly than go to statements and switches, and it eliminates the need for introducing a large number of labels in the program.”
关于 goto 语句不可取的观点并不新鲜。我记得读过明确的建议,说应将 goto 语句的使用限制在异常退出的情况,但我找不到出处了;大概是C. A. R. 霍尔提出的。在[1,第3.2.1节]中,沃思和霍尔在阐述case结构的必要性时也表达了类似观点:“和条件语句一样,它比 goto 语句和switch语句更清晰地反映了程序的动态结构,并且避免了在程序中引入大量标签。”
In [2] Guiseppe Jacopini seems to have proved the (logical) superfluousness of the go to statement. The exercise to translate an arbitrary flow diagram more or less mechanically into a jump - less one, however, is not to be recommended. Then the resulting flow diagram cannot be expected to be more transparent than the original one.
在[2]中,朱塞佩·雅各皮尼似乎证明了 goto 语句在逻辑上是多余的。然而,将任意流程图或多或少机械地转换为无跳转的流程图这种做法并不值得推荐。因为转换后的流程图不见得比原来的更清晰易懂。
References:
参考文献:
-
Wirth, Niklaus, and Hoare C. A. R. A contribution to the development of ALGOL. Comm. ACM 9 (June 1966), 413 - 432.
尼克劳斯·沃思,C. A. R. 霍尔。对ALGOL语言发展的贡献。《美国计算机协会通讯》1966年6月第9期,413 - 432页。 -
BÖhm, Corrado, and Jacopini Guiseppe. Flow diagrams, Turing machines and languages with only two formation rules. Comm. ACM 9 (May 1966), 366 - 371.
科拉多·博姆,朱塞佩·雅各皮尼。流程图、图灵机以及仅有两条形成规则的语言。《美国计算机协会通讯》1966年5月第9期,366 - 371页。
Edsger W. Dijkstra
埃德斯加·W·迪杰斯特拉
Technological University
埃因霍温理工大学
Eindhoven, The Netherlands
荷兰埃因霍温
via:
- Go_To_Statement_Considered_Harmful.1968
https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf

被折叠的 条评论
为什么被折叠?



