作者noctem (noctem)
看板PLT
标题[闲聊] Go To 有害论大笔战
时间Sat Jul 4 20:38:58 2009
刚写完这个,觉得贴这里应该蛮合适...
这里可以借我打广告吗? :)
http://www.iis.sinica.edu.tw/~scm/ncs/?p=9
-----------------------
Go To 有害论大笔战
写函数语言简介时提到了结构化程式设计与 GOTO, 於是顺便又复习了这串笔
战。
◎ Go To 有害论
1968 年,Dijkstra 投了一篇文章到 Communications of the ACM。「几年
前我便观察到,一个程式员的品质是其程式中 go to 密度的递减函数。」他
说,「後来我发现了为什麽 go to 的使用有这麽严重的後果,并相信所有『
高阶』语言都应该把 go to 废除掉。」
Dijkstra 原本下的标题是 ‘A Case Against the Goto Statement’ (一
个反对 go to 的理由)。CACM 编辑 Niklaus Wirth 神来一笔地把标题改为
‘Go To Statement Considered Harmful’ (Go To 有害!)。读者看了标
题已先是一惊,而 Dijkstra 写的内文也不改他一贯的犀利语气,用流行话
讲,战意可浓厚呢。Wirth 的神来一笔也带起了计算学界用 ‘X
considered harmful‘ 当文章标题的风潮,直到终於有人受不了为止。
为什麽 go to 不好? Dijkstra 说,一个变数代表什麽意义要看其上下文。
一个程式用 n 记录房间里的人数,在大部分时候 n 代表的是「目前房间里
的人」。但在观察到又有一个人进房间後、把 n 递增的指令前的这段程式区
块中,n 的值代表的是「目前房间里的人数减一」。因此,要正确诠释程式
的状态,必须知道程式执行的历史,或着说,知道现在「算到哪」了。
怎麽谈「算到哪了」?如果是一直线执行下来的程式,我们只要手指一伸,
说「到这里」,就可以了。如果是有回圈的程式,我们可能得说「现在在回
圈的这个地方,回圈已经执行了 i 次」。如果是在副程式中,我们可能得说
「现在执行到副程式 p 的这一点;p 刚刚被 q 呼叫,呼叫点在一个回圈中
,已经执行了 i 次。」我们可能需要一个堆叠来放这些数字。但无论如何,
程式的执行虽是动态的,上述资讯仍可用少量的静态(意即由程式结构可推
论出的)资讯来描述。
如果可以多用一个技术名词:在上述的情形中,由於程式中每点的执行历史
可用相对少量资讯表达,我们仍不难在程式里面放一些断言(assertion),
说「凡是执行到这里的时候,这些事情一定会成立。」
如果有 go to 呢?那就麻烦了。因为电脑在执行某个指令前,可能是从程式
中许许多多 go to 之中的其中一个跳过来的。要谈某个变数的性质也几乎变
得不可能了。
◎ 「Go To 有害论」有害论!
Dijkstra 这篇文章後来成为结构化程式论战最有名的文章之一。长达 19 年
之後,Frank Rubin 投了一篇文章到 CACM, 标题为 ‘GOTO Considered
Harmful’ Considered Harmful — go to 有害论才是有害的!Rubin 说,
「虽然 Dijkstra 的说法既太学术又缺乏说服力」,却似乎烙到每个程式员
的心里了。
「Go to 有害」的说法固然一鸣惊人,却也使得後人不自觉地陷入一方不断
提出「用 go to 会比较好」的难题,另一方不断解题的无意义虚耗。Rubin
这次出的题目是这样的:令 X 为 N × N 的整数阵列。如果 X 的第 i 行
全都是零,请印出 i。如果不只一行,印出最小的 i.
Rubin 找了一些惯用 go to 和不用 go to 的程式员来解题,认为前者的程
式又快又清楚。後者通常花了更多的时间,写出很复杂的解答。
你会怎麽写这题呢?
◎ 「『Go To 有害论』有害论」有害论?
以後几个月的 CACM 果然很热闹。编辑收到许多回应,两个月後刊出了其中
五篇。编辑选用的标题?当然罗,『‘GOTO Considered Harmful’
Considered Harmful』 Considered Harmful? –「『Go To 有害论』有害论
」有害?
有些回应赞同 Rubin,有些则否。但後者的表现并不是很好。有人建议结构
化语言还需要新的控制结构,例如可提早终止的 for 回圈。有人认为这是
Pascal 没有 break 指令之故。有的提出了他们的程式,但老实说不容易看
出好在哪里。
Dijkstra 有点看不下去了。
◎ 「令人失望的对谈」
同一个月,Dijkstra 写了一篇短文 On a somewhat disappointing
correspondence(关於一次令人失望的对谈)。「我以为我想讲的都有人会
讲,因此没回 Frank Rubin 的信。但两个月後发表的五篇回信中,竟没人做
到。」
接着,Dijkstra 不客气地开骂了,从大小写的使用 –「我以为到了现在,
一个专业程式员该有高一点的自我要求了」、阵列应该从 0 算起 — 「我以
为到了现在,一个专业程式员该知道自然数从 0 开始的好处了」开始,接着
指出 Rubin 的三个程式中两个有错(都是结构化程式) –「我以为到了现
在,一个专业程式员该知道这种 bug 怎麽来的。」
Dijkstra 接着指出 Rubin 第三个程式的正确性要靠这个性质 — 如果逻辑
and 的第一个参数是 false, 第二个参数不用有结果。但这种运算元的数学
性质不好,用起来是很危险的。
最後,不知为什麽没人看出来,Rubin 的问题只需把同一个演算法 — 「有
界线性搜寻」(bounded linear search)套用两次即可。Dijkstra 示范了这
种搜寻该使用什麽回圈不变量(loop invariant),如何推导、使用。他认为
这都应已是基本常识才对。程式设计研究已发展多年,依他的标准,一个
1987 年的专业程式员应该
要能看得出来 Rubin 的问题适合用同一个演算法一层套一层地做出来;
要知道有界线性搜寻定理;
要能导出这个定理和其证明;
而且也不迟疑去用它;
不用浪费时间指出(Dijkstra 本文示范的演算法中)有个变数可以省掉;
能用简单、不杂乱的回圈;
等等。
也许他的意思是,当时不是比赛省一两个记忆体空间或一两个指令的时代;
他在意的是组织程式、以及程式的证明的清晰思路。如果有已经证明出的性
质和程式推导模式可以使用,他觉得就该用,不应见树不见林。
他的期望,现在实现了多少呢?
◎ 後续…
Dijkstra 锐利的风格一直没变。他的 Turing Award 演讲题为「谦卑的程式
员」,意谓程式员面对问题的复杂度应有着谦卑的态度,善用我们有的数学
工具和方法。但同年又有人在 ACM SIGCSE Bulletin 上投稿 ‘The
arrogant programmer: Dijkstra and Wegner considered harmful‘ (傲慢
的程式员:Dijkstra 与 Wegner 是有害的),与其针锋相对。
另一方面,Communications of ACM 毕竟不是靠炒话题卖钱的杂志,在这场
论战後便决定不再刊登立场过於强烈的文章了。
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 114.186.101.154
1F:→ prag222:记得刚念大学的时候写作业教授也有提醒我少用GOTO 08/15 23:50
2F:→ prag222:不过我写按键精灵还蛮常用GOTO的 08/15 23:51
3F:→ prag222:不过後来学别人就比较常用模组化了 08/15 23:51