2008年3月8日星期六

失败的英雄-查尔斯·巴贝奇(Charles Babbage)


今天出版的许多计算机书籍扉页里,都登载着这位先生的照片:宽阔的额,狭长的嘴,锐利的目光显得有些愤世嫉俗,坚定的但绝非缺乏幽默的外貌,给人以一种极富深邃思想的学者形象,有人或许知道他的大名——查尔斯•巴贝奇(Charles Babbage)。
  巴贝奇,1792年出生在英格兰西南部的托特纳斯,是一位富有的银行家的儿子,后来继承了相当丰厚的遗产,但他把金钱都用于了科学研究。童年时代的巴 贝奇显示出极高的数学天赋,考入剑桥大学后,他发现自己掌握的代数知识甚至超过了教师。毕业留校,24岁的年青人荣幸地受聘担任剑桥“路卡辛讲座”的数学 教授。这是一个很少有人能够获得的殊荣,牛顿的老师巴罗是第一名,牛顿是第二名。假若巴贝奇继续在数学理论领域耕耘,他本来是可以走上鲜花铺就的坦途。然 而,这位旷世奇才却选择了一条无人敢于攀登的崎岖险路。
  事情恐怕还得从法国讲起。18世纪末,法兰西发起了一项宏大的计算工程——人工编制《数学用表》,这在没有先进计算工具的当时,可是件极其艰巨的工 作。法国数学界调集大批精兵强将,组成了人工手算的流水线,算得个天昏地暗,才完成了17卷大部头书稿。即便如此,计算出的数学用表仍然存在大量错误。
  据说有一天,巴贝奇与著名的天文学家赫舍尔凑在一起,对两大部头的天文数表评头论足,翻一页就是一个错,翻两页就有好几双。面对错误百出的数学表,巴 贝奇目噔口呆,他甚至喊出声来:“天哪,但愿上帝知道,这些计算错误已经充斥弥漫了整个宇宙!”这件事也许就是巴贝奇萌生研制计算机构想的起因。巴贝奇在 他的自传《一个哲学家的生命历程》里,写到了大约发生在1812年的一件事:“有一天晚上,我坐在剑桥大学的分析学会办公室里,神志恍惚地低头看着面前打 开的一张对数表。一位会员走进屋来,瞧见我的样子,忙喊道:‘喂!你梦见什么啦?’我指着对数表回答说:‘我正在考虑这些表也许能用机器来计算!’”
  巴贝奇的第一个目标是制作一台“差分机”,那年他刚满20岁。他从法国人杰卡德发明的提花织布机上获得了灵感,差分机设计闪烁出了程序控制的灵光—— 它能够按照设计者的旨意,自动处理不同函数的计算过程。1882年,巴贝奇小试锋芒,初战告捷,第一台差分机呱呱坠地。但是,这一“小试”也耗去了整整 10年。这是因为当时的工业技术水平极差,从设计绘图到零件加工,都得自己亲自动手。好在巴贝奇自小就酷爱并熟悉机械加工,车钳刨铣磨,样样拿手。在他孤 军奋战下造出的这台机器,运算精度达到了6位小数,当即就演算出好几种函数表。以后实际运用证明,这种机器非常适合于编制航海和天文方面的数学用表。
  “春风得意马蹄疾”。成功的喜悦激励着巴贝奇,他连夜奋笔上书皇家学会,要求政府资助他建造第二台运算精度为20位的大型差分机。英国政府看到巴贝奇 的研究有利可图,破天荒地与科学家签订了第一个合同,财政部慷慨地为这台大型差分机提供出1.7万英镑的资助。巴贝奇自己也贴进去1.3万英镑巨款,用以 弥补研制经费的不足。在当年,这笔款项的数额无异于天文数字——有关资料介绍说,1831年约翰•布尔制造一台蒸汽机车的费用才784英磅。
  然而,英国政府和巴贝奇都失了算,第二台差分机在剑桥的“阴沟”里面翻了船!我们可以设身处地替巴贝奇想一想,第二台差分机大约有25000个零件, 主要零件的误差不得超过每英寸千分之一,即使用现在的加工设备和技术,要想造出这种高精度的机械也绝非易事。巴贝奇把差分机交给了英国最著名的机械工程师 约瑟夫•克莱门特所属的工厂制造,但工程进度十分缓慢。设计师心急火燎,从剑桥到工厂,从工厂到剑桥,一天几个来回。他把图纸改了又改,让工人把零件重做 一遍又一遍。年复一年,日复一日,直到又一个10年过去后,巴贝奇依然望着那些不能运转的机器发愁,全部零件亦只完成不足一半数量。参加试验的同事们再也 坚持不下去,纷纷离他而去如鸟兽散。巴贝奇独自苦苦支撑了第三个10年,终于感到自己再也无力回天。那天清晨,巴贝奇蹒跚走进车间。 偌大的作业场空无一人,只剩下满地的滑车和齿轮, 四处一片狼籍。 他呆立在尚未完工的机器旁, 深深地叹了口气, 终于“怆然而涕下”。在痛苦的煎熬中,他无计可施,只得把全部设计图纸和已完成的部分零件送进伦敦皇家学院博物馆供人观赏。

1842年,在巴贝奇的一生中是极不平常的一年。那年冬天,伦敦的气候格外寒冷,巴贝奇的身心全都冷得发颤。英国政府宣布断绝对他的一切资助,连科学 界的友人都用一种怪异的目光看着他。英国首相讥讽道:“这部机器的唯一用途,就是花掉大笔金钱!”同行们讥笑他是“愚笨的巴贝奇”。皇家学院的权威人士, 包括著名的天文学家艾瑞等人,都公开宣称他的差分机“毫无任何价值”……
  就在这痛苦艰难的时刻,一缕春风悄然吹开巴贝奇苦闷的心扉。他意外地收到一封来信,写信人不仅对他表示理解而且还希望与他共同工作。娟秀字体的签名,表明了她不凡的身份——伯爵夫人。
  接到信函后不久,巴贝奇实验室门口走进来一位年轻的女士。只见她身披素雅的斗蓬,鬓角上斜插一束白色的康乃馨,显得那么典雅端庄,面带着衿持的微笑, 向巴贝奇弯腰行了个致敬礼。巴贝奇一时愣在那里,他与这位女士似曾相识,又想不起曾在何处邂逅。女士落落大方地作了自我介绍,来访者正是那位伯爵夫人。
  “您还记得我吗?”女士低声问道,“十多年前,您还给我讲过差分机原理。”看到巴贝奇迷惑的眼神,她又笑着补充说:“您说我像野人见到了望远镜。”巴 贝奇恍然大悟,想起已经十分遥远的往事。面前这位俏丽的女士和那个小女孩之间,依稀还有几分相似。
  原来,夫人本名叫阿达•奥古斯塔,是英国大名鼎鼎的诗人拜伦之独生女。她比巴贝奇的年龄要小20多岁,1815年才出生。阿达自小命运多蹇,来到人世 的第二年,父亲拜伦因性格不合与她的母亲离异,从此别离英国。可能是从未得到过父爱的缘由,小阿达没有继承到父亲诗一般的浪漫热情,却继承了母亲的数学才 能和毅力。那还是阿达的少女时代,母亲的一位朋友领着她们去参观巴贝奇的差分机。其他女孩子围着差分机叽叽喳喳乱发议论,摸头不是脑。只有阿达看得非常仔 细,她十分理解并且深知巴贝奇这项发明的重大意义。
  或许是这个小女孩特殊的气质,在巴贝奇的记忆里打下了较深的印记。他赶紧请阿达入座,并欣然同意与这位小有名气的数学才女共同研制新的计算机器。
  就这样,在阿达27岁时,她成为巴贝奇科学研究上的合作伙伴,迷上这项常人不可理喻的“怪诞”研究。其时,她已经成了家,丈夫是洛甫雷斯伯爵。按照英国的习俗,许多资料在介绍里都把她称为“洛甫雷斯伯爵夫人”。
  30年的困难和挫折并没有使巴贝奇折服,阿达的友情援助更坚定了他的决心。还在大型差分机进军受挫的1834年,巴贝奇就已经提出了一项新的更大胆的 设计。他最后冲刺的目标,不是仅仅能够制表的差分机,而是一种通用的数学计算机。巴贝奇把这种新的设计叫做“分析机”,它能够自动解算有100个变量的复 杂算题,每个数可达25位,速度可达每秒钟运算一次。今天我们再回首看看巴贝奇的设计,分析机的思想仍然闪烁着天才的光芒。
  巴贝奇首先为分析机构思了一种齿轮式的“存贮库”,每一齿轮可贮存10个数,总共能够储存1000个50位数。分析机的第二个部件是所谓“运算室”, 其基本原理与帕斯卡的转轮相似,但他改进了进位装置,使得50位数加50位数的运算可完成于一次转轮之中。此外,巴贝奇也构思了送入和取出数据的机构、以 及在“存储库”和“运算室”之间运输数据的部件。他甚至还考虑到如何使这台机器处理依条件转移的动作。一个多世纪过去后,现代电脑的结构几乎就是巴贝奇分 析机的翻版,只不过它的主要部件被换成了大规模集成电路而已。仅此一说,巴贝奇就当之无愧于计算机系统设计的“开山鼻祖”。
  俏阿达“心有灵犀一点通”,她非常准确地评价道:“分析机‘编织’的代数模式同杰卡德织布机编织的花叶完全一样”。于是,为分析机编制一批函数计算程 序的重担,落到了数学才女柔弱的肩头。阿达开天辟地第一回为计算机编出了程序,其中包括计算三角函数的程序、级数相乘程序、伯努利函数程序等等。阿达编制 的这些程序,即使到了今天,电脑软件界的后辈仍然不敢轻易改动一条指令。人们公认她是世界上第一位软件工程师,港台地区的书刊,还把她请上了软件界“开山 祖师奶”的赫赫宝座。众所周知,美国国防部据说是花了250亿美元和10年的光阴,把它所需要软件的全部功能混合在一种计算机语言中,希望它能成为军方数 千种电脑的标准。1981年,这种语言被正式命名为ADA语言,使阿达的英名流传至今。
  不过,以上讲的都是后话,殊不知巴贝奇和阿达当年处在怎样痛苦的水深火热之中!由于得不到任何资助,巴贝奇为把分析机的图纸变成现实,耗尽了自己全部 财产,搞得一贫如洗。他只好暂时放下手头的活,和阿达商量设法赚一些钱,如制作什么国际象棋玩具,什么赛马游戏机等等。为筹措科研经费,他们不得不“下 海”搞“创收”。最后,两人陷入了惶惶不可终日的窘境。阿达忍痛两次把丈夫家中祖传的珍宝送进当铺,以维持日常开销,而这些财宝又两次被她母亲出资赎了回 来。
  贫困交夹,无休无止脑力劳动,阿达的健康状况急剧恶化。1852年,怀着对分析机成功的美好梦想和无言的悲怆,巾帼软件奇才魂归黄泉,香消魄散,死时年仅36岁。
  阿达去后,巴贝奇又默默地独自坚持了近20年。晚年的他已经不能准确地发音,甚至不能有条理地表达自己的意思,但是他仍然百折不挠地坚持工作。
  上帝对巴贝奇和阿达太不公平!分析机终于没能造出来,他们失败了。巴贝奇和阿达的失败是因为他们看得太远,分析机的设想超出了他们所处时代至少一个世 纪!然而,他们留给了计算机界后辈们一份极其珍贵的精神遗产,包括30种不同的设计方案,近2000张组装图和50000张零件图……,更包括那种在逆境 中自强不息,为追求理想奋不顾身的拼搏!
  1871年,为计算机事业而贡献了终生的先驱者终于闭上了眼睛。当时就有人把他的大脑用盐渍着保存起来,想经过若干年后,有更先进技术来研究他大脑特别的机制;现在的人们,当然更不会以成败来论英雄!

摘自百度博客:http://hi.baidu.com/cmpang/blog/item/d8bfbc519dd4bf18377abe16.html

C语言和Unix的发明史


在计算机发展的历史上,大概没有哪个程序设计语言像C那样得到如此广泛地流行;也没有哪个操作系统像UNIX那样获得计算机厂家和用户的普遍青睐和厚爱。它们对整个软件技术和软件产业都产生了深远的影响。而C和UNIX两者都是贝尔实验室的丹尼斯·里奇(Dennis MacAlistair Ritchie)和肯尼思·汤普森(Kenneth Lane Thompson)设计、开发的。因此,他们两人共同获得1983年度的图灵奖是情理中的事。我们先介绍汤普森,因为就C和UNN两者的关系而言,UNIX的开发在前,C是为了使UNIX具有可移植性而后来研制的;就里奇和汤普森两人的关系而言,他们两人当然是亲密的合作者,但汤普森在UNIX的开发中起了主导的作用,而里奇则在C的设计中起的作用更大一些。
汤普森1943年2月4日生于路易斯安娜州的新奥尔良,其父是美国海军战斗机的驾驶员。汤普森自幼的爱好有两个,一个是下棋,一个是组装晶体管收音机。他父亲为了发展孩子的智力和能力,在晶体管当时问世不久,价格不菲(每只晶体管约售10美元)的情况下,很舍得为汤普森买晶体管让他摆弄。由于爱好无线电,汤普森上加州大学伯克利分校时学的专业是电气工程,于1965年取得学士学位,第二年又取得硕士学位。求诩洌共渭恿送ㄓ枚ρЧ荆?General Dynamics Corporation)在伯克利实行的半工半读计划( work-study Program),因此既增长了知识,又积累了不少实践经验。


毕业以后,汤普森加盟贝尔实验室。虽然他学的是电子学,主要是硬件课程,但由于他半工半读时在一个计算中心当过程序员,对软件也相当熟悉,而且更加偏爱,因此很快就和里奇一起被贝尔派到MIT去参加由ARPA出巨资支持的MAC项目,开发第二代分时系统MULTICS。但就在项目完成前不久,贝尔因感到开发费用太大,而成功的希望则不大而退出了该项目,把所有成员都调回贝尔。这使汤普森和里奇深感沮丧。返回贝尔以后,面对实验室中仍以批处理方式工作的落后的计算机环境,他们决心以他们在MAC项目中已学到的多用户、多任务技术来改造这种环境,以提高程序员的效率和设备的效率,便于人机交互和程序员之间的交互,用他们后来描写自己当时的心情和想法的话来说,就是“要创造一个舒适、愉快的工作环境”。但他们意识到,贝尔领导人既然下决心退出MAC,就不可能支持他们的想法,不可能为之立项,提供资金和设备,他们只能悄悄干,自己去创造条件。1969年,万般无奈的汤普森在库房中偶然发现一台已弃置不用的PDP-7,大喜过望,立即开始用它来实施他们的设想。但开头是十分困难的,因为这q PDP-7除了有一个硬盘、一个图形显示终端和一台电传打字机这些硬设备外,什么软件也没有。

他们只能在一台 GE 645大型机上编程、调试,调通以后穿孔在纸带上,再输入PDP-7。以这种“可怕的”工作方式开发两年以后,连这台PDP-7也损坏得不能再用了。这时,他们听到一个消息,实验室的专利部需要一个字处理系统以便处理专利申请书(贝尔每年要提出不少专利申请),汤普森立即找到上级自告奋勇承担这一开发任务,在这个冠冕堂皇的借口下,他们申请到了一台新的、设备完善的PDP- 11,这才使开发工作顺利地真正开展起来。

汤普森以极大的热情和极高的效率投入工作。开发基本上以每个月就完成一个模块(内核,文件系统,内存管理,I/O……)的速度向前推进,到1971年底,UNIX基本成形。UNIX这个名称是从MUL-TICS演变而来的:他们变MULTI为UNI,变CS为X。为了向上级“交差”,UNIX首先交给实验室的专利部使用,3个打字员利用UNIX输人贝尔当年的专利申请表,交口称赞系统好用,大大提高了工作效率,这样,UNIX迅速从专利部推广到贝尔的其他部门,又从贝尔内部推向社会。贝尔实验室的领导人终于认识到了UNIX的巨大价值,把它注册成为商标(但有趣的是,由于法律上的原因,注册商标及版权被贝尔的上属公司AT&T取得),推向市场。贝尔的一个行政长官甚至宣称,在贝尔的无数发明中,UNIX是继晶体管之后的最重要的一项发明。著名的国际咨询公司 IDC的高级分析员 Huie Bruce Kin估计,1985年单是美国就有27万7千个计算机系统使用UNIX,1990年这个数字增长至210万。目前世界上UNIX的安装数量超过500万套,用户数达到3000万。

UNIX之所以获得如此巨大的成功,主要是它采用了一系列先进的技术和措施,解决了一系列软件工程的问题,使系统具有功能简单实用,操作使用方便,结构灵活多样的特点。它是有史以来使用最广的操作系统之一,也是关键应用中的首选操作系统。UNIX成为后来的操作系统的楷模,也是大学操作系统课程的“示范标本”。归纳起来,UNIX的主要特性如下:

1作为多用户多任务操作系统,每个用户都可同时运行多个进程。

2提供了丰富的经过精心编选的系统调用。整个系统的实现紧凑、简洁、优美。

3提供功能强大的可编程外壳(Shell)语言作为用户界面,具有简洁高效的特点。

4采用树形文件结构,具有良好的安全性、保密性和可维护性。

5提供多种通信机制,如管道通信、软中断通信、消息通信、共享存储器通信和信号灯通信。

6采用进程对换内存管理机制和请求调页内存管理方式实现虚存,大大提高了内存使用效率。

7系统主要用C编写,不但易读、易懂、易修改,更极大提高了可移植性。

由于以上特点,也由于看好UNIX的应用和前景,各大公司纷纷推出自己的 UNIX版本,如 IBM的 AIX,SUN的Solaris,HP的 HP-UX, SCO的 UNIXWARE和 open Server, DEC(已被 Compaq收购)的digital UNIX,以及加州大学伯克利分校的 UNIX BSD。这些 UNIX各具特色,形成百花齐放的局面。到20世纪op年代,UNIX版本多达100余个。UNIX的标准化工作则经历了一个复杂的过程。最早是UNIX用户协会从20世纪80年代开始此项工作,1984年颁布了试用标准。后来此工作被IEEE接收和继承,制定了多个基于UNIX的“仍移植操作系统环境”标准,即POSIX。而计算机厂家在UNIX标准上则分裂为两大阵营,即以AT&T和SUN为首的UNIX国际(UI)和以IBM、HP、DEC为首的开放系统基金会(OSF)。分裂和竞争一方面促进了UNIX技术的迅猛发展,另外一方面则引起用户的困惑,不利于UNIX市场的健康发展。因此,1993年3月,两大阵营终于走到一起,成立了“公共开发软件环境”组织(COSE),以实现UNIX系统的统一化。1993年10月,Novell公司将从AT&T购得的UNN商标权无偿移交给开放系统标准化组织X/OPEN,这样,UNIX商标不再受某一厂商控制,而由中性的国际组织管理。1995年,关于UNIX的两个重要标准 CDE(规定 UNIX的图形界面)和 UNIX 95(规定 UNIX的应用程序界面,也叫Spec.1170)正式颁布,为整个UNIX的标准化打下了基础。1998年,IBM、Intel和SC0三家业界巨头在加利福尼亚的蒙特雷(Monterey)聚会,进一步商讨了UNIX统一问题,制定了蒙特雷计划。这个计划结合了IBM公司的AIX、NUMA-Q和SCO的UnixWare技术,建立一条企业级商用 UNIX产品线,使之能同时运行在 Intel IA-32、IA-64和 IBM PowerPC处理器之上,平台适用范围将覆盖从部门级服务器到大型数据库中心的超级服务器。目前,AIX和UnixWare已经相互融合并达到了二进制级的互操作性。

应该指出,目前操作系统平台形成了 UNIX、Windows NT和 LINUX三强鼎立的局面,而由芬兰大学生 Linus Torvalds推出的 LINUX本身实际上也是UNIX见的一个变种。

由于功能强劲,用途多样,使用方便,因此有人把UNIX称作软件中的“瑞士多用途折叠刀”(或叫“瑞士军刀”)。

汤普森本人围绕UNIX的开发工作于1978年结束。之后他从事过的项目有 Plan 9,这是另一个操作系统,旨在提高分布式计算的性能。 Plan 9用单一协议查询不同的资源、过程、程序和数据,并与之进行通信,为访问分布于由服务器、终端和其他设备组成的网络上的计算资源提供一个统一的方式,尤其适合于那些要求安全运行的Web服务器。 Plan 9的设计思路是惊人的,它小而功能强大,而且非常灵活,是 UNIX和 LINUX的竞争产品。 Plan 9早在 20世纪 80年代后期就已设计成型,目前的 Plan 9第三版是 1995年推出的。但 Plan9至今只限于贝尔实验室内部使用,没有推广和流行。最近(2000年6月),贝尔实验室采取惊人措施,免费开放 Plan 9源代码,以便让实验室以外的人使用 Plan 9。贝尔实验室的这一举措也许会像当年推出UNIX一样,在软件界引起一次新的震荡。此外,鉴于汤普森自幼爱好下棋,他还建造过一台名为Belle的下棋计算机,还与康顿(Joseph Condon)合作,在 PDP- 11/23和 PDP- 11/70上编制了下棋程序,这个程序从1979年到1983年在连续几届计算机下棋世界比赛中都独占鳌头,成为“四连冠”,同时也成为被美国围棋联盟USCF授予“大师”称号的第一个下棋程序。这个程序每秒可观察15万个棋步,与现今的IBM的“深蓝”当然无法相比,但在当时却是一个了不起的成就。

里奇比汤普森年长2岁,1941年9月9日生于纽约州的勃浪克斯山庄(Bronxville),但在9岁时移居新泽西州的塞米特。里奇的父亲是一个电气工程师,在贝尔实验室的交换系统工程实验室当主任,因此,里奇一家可谓“呗尔世家”。里奇中学毕业后进哈佛大学学物理,并于1963年获得学士学位。其间,哈佛大学有了一台UNIVAC I,并给学生开设有关计算机系统的课程,里奇听了以后产生了很大的兴趣。毕业以后他在应用数学系攻读博士学位,完成了一个有关递归函数论方面的课题,写出了论文,但不知什么原因没有答辩,没有取得博士学位,他就离开了哈佛,于1967年进入贝尔实验室,与比他早一年到贝尔的汤普森会合,从此开始了他们长达数十年的合作。

前面说过,UNIX的开发是以汤普森为主的,那末,为什么文献资料中一提到UNIX,都一致地说是里奇和汤普森共同于发的,而且在“排名”上往往是里奇在前,汤普森在后呢?包括他们在1973年由ACM主办、IBM承办的操作系统原理讨论会上首次向社会推介UNIX的论文 The UNIX Time- Sharing System的署名,里奇也是第一作者,汤普森则为第二作者。里奇在UNIX开发中有些什么功劳呢?

这里有两个很重要的因素。首先,UNIX的成功应归功于它的创新。前面曾经提到,UNIX吸取与借鉴了MULTICS的经验,如内核,进程,层次式目录,面向流的I/0,把设备当作文件,等等。这是可以理解的,因为任何新事物必然是对原有事物的继承和发展。尤其是UNIX,毕竟没有正式立项,是汤普森、里奇等少数几个人偷偷干的,如果一切都要从头从新设计,那几乎是不可能的。但是UNIX在继承中又有创新,比如 UNIX采用一种无格式的文件结构,文件由字节串加句号组成。这带来两大好处:一是在说明文件时不必加进许多无关的“填充物”(类似于COBOL中的FILLER),二是任何程序的输出可直接用作其他任何程序的输入,不必经过转换。后面这一点叫做“流水”(piping),就是UNIX首创的。此外,像把设备当作文件,从而简化了设备管理这一操作系统设计中的难题,虽然不是UNIX的发明,但是实现上它采用了一些新方法,比MULTICS更高明一些。正是在这些方面,里奇发挥了很重要的作用,使UNIX独具特色。

其次,UNIX成功的一个重要因素是它的可移植性。正是里奇竭尽全力开发了C语言,并把UNIX用C重写了一遍,这才使它具有了这一特性。汤普森是用汇编语言开发UNIX的,这种语言高度依赖于硬件,由它开发的软件只能在相同的硬件平台上运行。里奇在由剑桥大学的里查德(M.Richard)于1969年开发的BCPL语言(Basic Combined Programming Language)的基础上,巧妙地对它进行改进、改造,形成了既具有机器语言能直接操作二进制位和字符的能力,又具有高级语言许多复杂处理功能如循环、转移、分支等的一种简单易学而又灵活、高效的高级程序设计语言。他们把这种语言称为C,一方面指明了继承关系(因为BCPL的首字母是B。有些资料说是汤普森先根据BCPL开发了一种称为B的语言,再由里奇根据B开发了C。这种说法并不太确切,因为我们在汤普森与里奇本人的叙述中,都没有见到有关B语言这一中间过程的说法),另一方面也反映了他们对软件追求简洁明了的一贯风格。C开发成功以后,里奇用C把U-NIX重写了一遍。我们这里用了“重写”这个词,因为文献资料在提到这件事时都是用的这一说法,显得很轻巧;实际上,里奇做的这件事本身就是“移植”,即把汤普森用汇编语言实现的UNIX改用C来实现,这决不是什么轻巧的工作,尤其是对UNIX这样的大型软件。这需要付出艰苦的劳动,也是一件需要创造性的工作。单是里奇此举就是可以大书特书的,而C作为可以不依附于UNIX的一个独立的软件产品,也自有其本身的巨大价值,在计算机发展史上可以写下浓重的一笔。C已经实现标准化,即ISO于1990年公布的ISO/IEC9899,它以 ANSIC为基础,是第一个支持多8位字符集的程序设计语言国际标准。

前述里奇和汤普森的论文 The UNIX Time-Sharing Symtem后来发表于 Communications of ACM,1974年 7月。 ACM 1983年在纪念该刊创刊25周年时曾经评选出刊登于其上的25篇文章称之为具有里程碑式意义的研究论文,该文就是其中之一。

除了论文以外,里奇还和凯尼汉(B.W.Kernighan)合著了一本介绍 C的专著:《C程序设计语言》(The C Programming Language, Prentice-Hall,1978,1988)。我们现在见到的大量论述C语言程序设计的教材和专著都是以本书为蓝本的。

汤普森和里奇在成名以后,都没有走办公司、挣大钱的路,他们仍然在贝尔做他们喜爱做的事,而且还一直保持着他们历来的生活习惯和作风,常常工作到深夜,在贝尔是出名的“夜猫子”。里奇在接受记者采访时,就自称自己是 definitely a night person。里奇 1983年接受图灵奖时已经42岁,但仍然单身。

ACM于1983年10月举行的年会上向汤普森和里奇颁奖。有趣的是,ACM当年决定新设立一个奖项叫“软件系统奖”(Software Sys-tem Award),奖励优秀的软件系统及其开发者。而首届软件系统奖评选结果中奖的也是UNIX。这样,这届年会上汤普森和里奇成了最受关注的大红人,他们同时接受了“图灵”和“软件系统”两个大奖,这在ACM历年的颁奖仪式上是从来没有过的。里奇发表的图灵奖演说题为“对软件研究的反思”(Reflections on Software Research),汤普森的演说题为“对深信不疑的信任的反思”(Reflections on Trusting Trust),它们刊载于 Communications of ACM,1984年 8月,757- 763页,或见《前20年 ACM图灵奖演说集》(ACM Turing Award Lectures——The First 20 Years: 1966- 1985, ACM Pr.), 163- 178页。里奇在演说中强调了UNIX成功的因素,包括比较长的酝酿时期和他们在开发时没有商业上的压力。里奇认为,对研究工作而言,受到过份的关注反而会影响创造力和自由的交换意见。汤普森在演说中谦虚地自称是“程序员”(在他以前获图灵奖的狄克斯特拉、霍尔、克努特和弗洛伊德也都这样称呼过自己)。同里奇一样,汤普森强调了开发程序系统时环境和背景的重要性。

除图灵奖外,汤普森和里奇还从两个著名的杂志那里获得奖励和荣誉,一是《电子学》(Electronics)周刊,它从1974年起设立“成就奖”(achievement award),奖励在电子线路、工艺、仪器设备等方面有重大发明创造的科学家,曾经获得该项奖励的人中包括著名的提出“摩尔定理”的 Intel总裁摩尔(G. E. Moors),MOS工 的发明者里趣曼(P.Richman),发明软盘的舒格特(A.F.Shugart)等。但由于UNIX和C的巨大成功和影响,使1982年的这个奖破例授予了软件开发者汤普森和里奇。二是读者面很广的Datamation月刊,它于1987年创刊30周年时建立了一个“计算机名人堂”(Hall of Fame),首批 30位名人中包括图灵、冯·诺伊曼及多位图灵奖得主,如克努特(D.Knuth),巴克斯(J.Backus),麦卡锡(J.McCarthy)等。第二年首次增补名人,就选中了汤普森和里奇。

阿兰-图灵(Alan Turing)


2004年6月7日,是英国数学家、被称为计算机科学之父的阿兰-图灵(Alan Turing)去世五十周年的日子。1954年的6月7日,42岁的图灵过早离开了人世。图灵的过早去世,至少对当年的世界计算机科学领域来说,是一个难以估量的巨大损失。

  计算机科学发展到半个世纪后的今天,当这门科学已经如此广泛深刻的影响到全世界的文明进步和绝大部分人的工作与生活的时候,人们理应衷心的感谢象图灵这样做出开创性贡献的人。正是归功于图灵、冯-诺伊曼等人的才智和辛勤工作,让人们更早的享受到了电脑技术的神奇和效率。可以这么说,最近半个世纪以来,世界计算机科学界的重大进步,离不开图灵等人的理论奠基作用和多方面的开创性研究成果。图灵是当之无愧的计算机科学和人工智能之父。

  学习计算机科学的大学生都应该知道,在计算机基础理论中有著名的“图灵机”和“图灵测试”。这些理论简洁的概括了图灵伟大贡献的一部分:他是第一个提出利用某种机器实现逻辑代码的执行,以模拟人类的各种计算和逻辑思维过程的科学家。而这一点,成为了后人设计实用计算机的思路来源,成为了当今各种计算机设备的理论基石。当今计算机科学中再常用不过的程序语言、代码存储和编译等基本概念,就是来自图灵的原始构思。

  了解世界计算机科学发展进程的人也应该知道,美国计算机学会(ACM)的年度“图灵奖”,自从1966年设立以来,一直是世界计算机科学领域的最高荣誉,相当于计算机科学界的诺贝尔奖。图灵奖已经被先后授予给了47位计算机科学界的杰出人物,其中包括关系数据库理论的开创者Edgar Codd、程序语言和算法理论的知名科学家Dijkstra、UNIX操作系统的开创者Dennis Ritchie、面向对象程序设计理论的奠基人以及苹果个人电脑基于鼠标的GUI界面(也就是WINDOWS图形界面的最原始来源)的首创者Alan Kay、Fortran语言的设计者John Backus、IBM-RISC体系结构的创立者John Cocke等大名鼎鼎的计算机科学家。这个以图灵的名字命名的大奖,代表着几十年来世界计算机科学的重大进步和创新,代表着计算机科学和相关技术产业的一次次质的飞跃,同时,也代表着计算机科学界对图灵的崇高敬意。

  图灵的诞辰和去世纪念日,都在六月份。然而,从某种意义上来说,他的去世纪念日更显得特别。图灵的诞辰,只是象其他无数普通人那样,来到这个世界上。而图灵的过早离世,却是当年愚昧落后的社会观念导致的。对同性恋者的无知和偏见,正是杀害图灵的幕后凶手。如今的英国以及世界上其它很多地方,已经从半个多世纪前的落后观念和政策中改变,走向了尊重、平等和反对歧视的现代社会。今天,人们在纪念图灵的同时,除了敬仰和感佩图灵为计算机科学做出的杰出贡献之外,更应该懂得尊重和珍视每一个不同的人。正是每一个各自不同的善良的人,在以不同的方式让我们的世界更加美好。假如图灵能够快乐的多活在世上十年、二十年或者更久,凭着他的才华智慧和探索精神,说不定,我们当今世界的计算机科学以及所有被直接或间接影响到的方方面面,都会更加向前推进。歧视和偏见,只会阻碍社会的文明进步,尊重和包容,才能带来社会的繁荣美好。这方面的思考,正是我们纪念图灵去世五十周年的意义所在。

  作为个人,图灵是一个同性恋者。不论你在个人观念上是理解或不理解同性爱,有一点是无法否认的:图灵是一个有深邃思想和敏锐智慧的人,图灵是一个勤奋工作和勇于探索的人,图灵是一个广受世人尊敬的人,图灵为我们的社会做出了不可磨灭的贡献。我们应该对所有为人类做出伟大贡献的人表达敬意,包括其中的同性恋者和异性恋者,包括阿兰-图林。

  阿兰-图灵(Alan Turing,也被译作阿兰-图林)生平简介(部分资料参考自Andrew Hodges所著的图灵传记“Alan Turing: the Enigma”):

  1912年6月23日,出生于英国伦敦。
  1931年-1934年,在英国剑桥大学国王学院(King's College)学习。
  1932年-1935年,主要研究量子力学、概率论和逻辑学。
  1935年,年仅23岁的图灵,被选为剑桥大学国王学院院士。
  1936年,主要研究可计算理论,并提出“图灵机”的构想。
  1936年-1938年,主要在美国普林斯顿大学做博士研究,涉及逻辑学、代数和数论等领域。
1938-1939年,返回剑桥从事研究工作,并应邀加入英国政府破译二战德军密码的工作。
  1940年-1942年,作为主要参与者和贡献者之一,在破译纳粹德国通讯密码的工作上成就杰出,并成功破译了德军U-潜艇密码,为扭转二战盟军的大西洋战场战局立下汗马功劳。
  1943年-1945年,担任英美密码破译部门的总顾问。
  1945年,应邀在英国国家物理实验室从事计算机理论研究工作。
  1946年,这个时候,图灵在计算机和程序设计原始理论上的构思和成果,已经确定了他的理论开创者的地位。由于图灵的杰出贡献,年轻的他被英国皇室授予OBE爵士勋衔。
  1947年-1948年,主要从事计算机程序理论的研究,并同时在神经网络和人工智能领域做出开创性的理论研究。
  1948年,应邀加入英国曼彻斯特大学从事研究工作,担任曼彻斯特大学计算实验室副主任。
  1949年,成为世界上第一位把计算机实际用于数学研究的科学家。
  1950年,发表论文“计算机器与智能”,为后来的人工智能科学提供了开创性的构思。提出著名的“图灵测试”理论。
  1951年,从事生物的非线性理论研究。年仅39岁的图林,被选为英国皇家学会会员。
  1952年,在当年保守愚昧和冷战的时代,当警察得知图灵与同性朋友密切交往的消息之后,同性恋倾向的图灵被逮捕入狱。在法庭审判过程中,图灵明确告知人们,他认为自己没有做错什么事。在那个观念落后的年代,为了避免被判刑入狱,图灵被迫选择了为期一年的雌性激素注射的所谓“治疗”,才得以重新返回研究工作。
  1953年-1954年,继续在生物和物理学等方面的研究。被迫承受的对同性恋倾向的“治疗”,致使原本热爱体育运动的图灵在身心上受到极大的伤害。
  1954年6月7日,图灵被发现死于家中的床上。死因是氰化物中毒,警方调查结论是自杀。一代英灵,就此过早离去,成为人类科学史上的一大遗憾。

转自CSDN: http://dev.csdn.net/develop/article/71/71741.shtm

冯·诺依曼小传


冯·诺依曼(J.Von Neum ann)是本世纪最伟大的科学家之一。 他1913年出生于匈牙利首都布 达佩斯,6岁能心算8位数除法,8岁学会微积分,12岁读懂了函数论。通过刻苦 学习, 在17岁那年,他发表了第一篇数学论文,不久后掌握七种语言,又在最 新数学分支——集合论、泛函分析等理论研究中取得突破性进展。22岁,他在 瑞士苏黎士联邦工业大学化学专业毕业。 一年之后,摘取布达佩斯大学的数学博士学位。 转而攻向物理,为量子力学研究数学模型,又使他在理论物理学领域占据了突出的地位。

1928年, 美国数学泰斗韦伯伦教授聘请这位26岁的柏林大学讲师到美国任教, 冯·诺依曼从此到美国定居。1933年,他与爱因斯坦一起被聘为普林斯顿大学高等研究院的第一批终身教授。 虽然电脑界普遍认为冯·诺依曼是“电子计算机之父”,数学史界却坚持说, 冯·诺依曼是本世纪最伟大的数学家之一,他在遍历理论、拓扑群理论等方面作出了开创性的工作, 算子代数甚至被命名为“冯·诺依曼代数”。物理学界表示,冯·诺依曼在30年代撰写的《量子力学的数学基础》已经被证明对 原子物理学的发展有极其重要的价值,而经济学界则反复强调,冯·诺依曼建立的经济增长横型体系, 特别是40年代出版的著作《博弈论和经济行为》,使 他在经济学和决策科学领域竖起了一块丰碑。 1957年2月8日, 冯·诺依曼因患骨癌逝世于里德医院,年仅54岁。他对电脑科学作出的巨大贡献,永远也不会泯灭其光辉!

电子计算机之父

“电子计算机之父”的桂冠,被戴在数学家 冯·诺依曼头上, 而不是ENIAC的两位实际研究者,这是因为冯·诺依曼提出了现代电脑的体系结构。

1944年夏,戈德斯坦在阿贝丁车站等候去费城的火车,偶然邂逅闻名世界的大数学家冯·诺依曼教授。戈德斯坦抓住机会向数学大师讨教,冯·诺依曼和蔼可亲,耐心地回答 戈德斯坦的提问。听着听着,他敏锐地从这些数学问题里,察觉到不寻常事情。他反过来 向戈德斯坦发问,直问得年轻人“好像又经历了一次博士论文答辩”。最后,戈德斯坦毫 不隐瞒地告诉他莫尔学院的电子计算机项目。

从1940年起,冯·诺依曼就是阿贝丁试炮场的顾问,计算问题也曾使数学大师焦虑万分。他向戈德斯坦表示,希望亲自到莫尔学院看看那台正在研制之中的机器。从此,冯· 诺依曼成为了莫尔小组的实际顾问,与小组成员频繁地交换意见。年轻人机敏地提出各种设想,冯·诺依曼则运用他渊博的学识,把讨论引向深入,并逐步形成电子计算机的系统 设计思想。 在ENIAC尚未投入运行前, 冯·诺依曼就看出这台机器致命的缺陷,主要弊端是程序 与计算两分离。程序指令存放在机器的外部电路里,需要计算某个题目,必须首先用人工 接通数百条线路,需要几十人干好几天之后,才可进行几分钟运算。 冯·诺依曼决定起草一份新的设计报告,对电子计算机进行脱胎换骨的改造。他把新 机器的方案命名为“离散变量自动电子计算机”,英文缩写是“EDVAC”。

1945年6月,冯 ·诺依曼与戈德斯坦、勃克斯等人,联名发表了一篇长达101页纸的报告,即计算机史上著名的“101页报告”,直到今天,仍然被认为是现代电脑科学发展里程碑式的文献。报告明确规定出计算机的五大部件,并用二进制替代十进制运算。EDVAC方案的革命意义在 于“存储程序”,以便电脑自动依次执行指令。人们后来把这种“存储程序”体系结构的 机器统称为“诺依曼机”。由于种种原因,莫尔小组发生令人痛惜的分裂,EDVAC机器无法被立即研制。1946年6月, 冯·诺依曼和戈德斯坦、 勃克斯回到普林斯顿大学高级研究院,先期完成了另一台 ISA电子计算机(ISA是高级研究院的英文缩写),普林斯顿大学也成为电子计算机的研究中心。

直到1951年,在极端保密情况下,冯·诺依曼主持的EDVAC计算机才宣告完成,它不仅可应用于科学计算,而且可用于信息检索等领域,主要缘于“存储程序”的威力。 EDVAC只用了3563只电子管和1万只晶体二极管,以1024个44比特水银延迟线来储存程序和 数据,消耗电力和占地面积只有ENIAC的1/3。

最早问世的内储程序式计算机既不是ISA,也不是EDVAC,英国剑桥大学威尔克斯(M.Wilkes)教授,抢在冯·诺依曼之前捷足先登。 威尔克斯1946年曾到宾夕法尼亚大学参加冯·诺依曼主持的培训班,完全接受了冯· 诺依曼内储程序的设计思想。回国后,他立即抓紧时间,主持新型电脑的研制,并于1949 年5月,制成了一台由3000只电子管为主要元件的计算机,命名为“EDSAC”(电子储存程序计算机)。威尔克斯后来还摘取了1967年度计算机世界最高奖——“图林奖”。

在冯·诺依曼研制ISA电脑的期间,美国涌现了一批按照普林斯顿大学提供的ISA照片 结构复制的计算机。 如:洛斯阿拉莫斯国家实验室研制的MANIAC,伊利诺斯大学制造的 ILLAC。雷明顿·兰德公司科学家沃尔(W. Ware)甚至不顾冯·诺依曼的反对,把他研制的机器命名为JOHNIAC(“约翰尼克” ,“约翰”即冯·诺依曼的名字)。冯·诺依曼的大名已经成为现代电脑的代名词,1994年,沃尔被授予计算机科学先驱奖,而冯·诺依曼本人则被追授予美国国家基础科学奖。

转自CSDN http://blog.csdn.net/Soundboy/

2008年3月5日星期三

Go To Statement Considered Harmful by Edsger W. Dijkstra


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.
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 (as wise programmers aware of our limitations) 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. (You may think about this question in a very concrete manner: suppose that a process, considered as a time succession of actions, is stopped after an arbitrary action, what data do we have to fix in order that we can redo the process until the very same point?) If the program text is a pure concatenation of, say, assignment statements (for the purpose of this discussion regarded as the descriptions of single actions) 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."
When we include conditional clauses (if B then A), alternative clauses (if B then A1 else A2), choice clauses as introduced by C. A. R. Hoare (case[i] of (A1, A2,···, An)),or conditional expressions as introduced by J. McCarthy (B1 -> E1, B2 -> E2, ···, Bn -> En), the fact remains that the progress of the process remains characterized by a single textual index.
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.
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!
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!
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.
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
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."
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.

2008年3月4日星期二

软件危机

软件危机(Software Crisis) 是计算机软件在它的开发和维护过程中所遇到的一系列严重问题。概括地说,主要包含两方面的问题:如何开发软件,怎样满足对软件日益增长的需求;如何维护数量不断膨胀的已有软件。

“软件危机”使得人们开始对软件及其特性进行更深一步的研究,人们改变了早期对软件的不正确看法。早期那些被认为是优秀的程序常常很难被别人看懂,通篇充满了程序技巧。现在人们普遍认为优秀的程序除了功能正确,性能优良之外,还应该容易看懂、容易使用、容易修改和扩充。

程序设计语言虽然为计算机的应用开拓了无比广阔的前景,但游荡在软件世界的幽灵——“软件危机”依然存在。因为软件的开发不仅受到程序设计的方法、结构的制约,而且受到开发周期以及软件开发成本的限制,更重要的是软件质量的保障与其程序设计的正确性关系极大。如果所开发的软件其可靠性得不到保障,在运行中将会产生不堪设想的严重后果。

60年代中期以后,计算机硬件技术日益进步,计算的存贮容量、运算速度和可靠性明显提高,生产硬件的成本不断降低。计算机价格的下跌为它的广泛应用创造了极好的条件。在这种形势下,迫切要求计算机软件也能与之相适应。因而,一些开发大型软件系统的要求提了出来。然而软件技术的进步一直未能满足形势发展的需要,在大型软件的开发过程中出现了复杂程度高、研制周期长、正确性难以保证的三大难题。遇到的问题找不到解决办法,致使问题堆积起来,形成了人们难以控制的局面,出现了所谓的“软件危机”。

最为突出的例子是美国IBM公司于1963年~1966年开发的IBM360系列机的操作系统。该软件系统花了大约5 000人一年的工作量,最多时,有 1000人投入开发工作,写出近100万行的源程序。尽管投入了这么多的人力和物力,得到的结果却极其糟糕。据统计,这个操作系统每次发行的新版本都是从前一版本中找出1000个程序错误而修正的结果。可想而知,这样的软件质量糟到了什么地步。

难怪该项目的负责人F·D·希罗克斯在总结该项目时无比沉痛地说:“……正像一只逃亡的野兽落到泥潭中作垂死挣扎,越是挣扎,陷得越深,最后无法逃脱灭顶的灾难,……程序设计工作正像这样一个泥潭……一批批程序员被迫在泥潭中拼命挣扎,……,谁也没有料到问题竟会陷入这样的困境……。” IBM360操作系统的历史教训已成为软件开发项目中的典型事例被记入历史史册。

如果开发的软件隐含错误,可靠性得不到保证,那么在运行过程中很可能对整个系统造成十分严重的后果,轻则影响到系统的正常工作,重则导致整个系统的瘫痪,乃至造成无可挽回的恶性事故。如,银行的存款可能被化为乌有,甚至弄成赤字;工厂的产品全部报废,导致工厂破产。

1963年,美国用于控制火星探测器的计算机软件中的一个“,”号被误写为“·”,而致使飞往火星的探测器发生爆炸,造成高达数亿美元的损失。

为了克服这一危机,一方面需要对程序设计方法、程序的正确性和软件的可靠性等问题进行系列的研究;另一方面,也需要对软件的编制、测试、维护和管理的方法进行研究,从而产生了程序设计方法学。

1968年,E·W·代克斯特拉首先提出“GOTO语句是有害的”论点,向传统程序设计方法提出了挑战,从而引起了人们对程序设计方法讨论的普遍重视。众多著名的计算机科学家都参加了这种讨论。程序设计方法学也正是在这种广泛而深入的讨论中逐渐产生和形成的。

什么是程序设计方法学呢?简言之,程序设计方法学是讨论程序的性质、程序设计的理论和方法的一门学科。它包含的内容比较丰富,例如,结构程序设计,程序正确性证明,程序变换,程序的形式说明与推导、程序综合、自动程序设计等。在程序设计方法学中,结构程序设计占有十分重要的地位,可以说,程序设计方法学是在结构程序设计的基础上逐步发展和完善起来的。

什么是结构程序设计呢?至今仍众说纷纭,还没有一个严格的,又能被大家普遍接受的定义。1974年,D·格里斯将已有的对结构程序设计的不同解释归结为13种,其中,比较有代表性的如下:

结构程序设计是避免使用GOTO语句的一种程序设计;
结构程序设计是自顶向下的程序设计;
结构程序设计是一种组织和编制程序的方法,利用它编制的程序易于理解、易于修改;
程序结构化的一个主要功能是使程序正确性的证明容易实现;
结构程序设计对设计过程中的每一步去验证其正确性,这样便自动导致自我说明和自我捍卫的程序设计风格;

总之,结构程序设计讨论了如何将大规模的和复杂的流程图转换成一种标准的形式,使得它们能够用几种标准的控制结构(通常是顺序、分支和重复)通过重复和嵌套来表示。

上述定义或解释从不同角度反映了结构程序设计所讨论的主要问题。实质上,结构程序设计是一种进行程序设计的原则和方法,按照这种原则和方法可设计出结构清晰、容易理解、容易修改、容易验证的程序。

按照结构程序设计的要求设计出的程序设计语言称为结构程序设计语言。利用结构程序设计语言,或者说按结构程序设计的思想和原则编制出的程序称为结构化程序。

在60年代末和70年代初,关于GOTO语句的用法的争论比较激烈。主张从高级程序语言中去掉GOTO语句的人认为,GOTO语句是对程序结构影响最大的一种有害的语句,他们的主要理由是:GOTO语句使程序的静态结构和动态结构不一致,从而使程序难以理解,难以查错。去掉GOTO语句后,可直接从程序结构上反映程序运行的过程。这样,不仅使程序结构清晰,便于理解,便于查错,而且也有利于程序的正确性证明。

持反对意见的人认为,GOTO语句使用起来比较灵活,而且有些情形能提高程序的效率。若完全删去GOTO语句,有些情形反而会使程序过于复杂,增加一些不必要的计算量。

1974年,D·E·克努斯对于GOTO语句争论作了全面公正的评述,其基本观点是:不加限制地使用GOTO语句,特别是使用往回跳的GOTO语句,会使程序结构难于理解,在这种情形,应尽量避免使用GOTO语句。但在另外一些情况下,为了提高程序的效率,同时又不致于破坏程序的良好结构,有控制地使用一些GOTO语句也是必要的。用他的话来说就是:“在有些情形,我主张删掉GOTO语句;在另外一些情形,则主张引进GOTO语句。”从此,使这场长达10年之久的争论得以平息。

后来,G·加科皮尼和C·波姆从理论上证明了:任何程序都可以用顺序、分支和重复结构表示出来。这个结论表明,从高级程序语言中去掉GOTO语句并不影响高级程序语言的编程能力,而且编写的程序的结构更加清晰。

结构程序设计的思想体现在采用了一些比较行之有效的方法,在这些方法中较有代表性的是“逐步求精”方法。所谓“逐步求精”方法,就是在编制一个程序时,首先考虑程序的整体结构而暂时忽略一些细节问题,然后逐步地一层一层地细化直至用所选用的语言完全描述每一个细节,即得到所期望的程序为止。换言之,它是按照先全局后局部、先整体后细节、先抽象后具体的过程组织人们的思维活动,使得编写出的程序结构清晰、容易理解、容易验证、容易修改。“逐步求精”方法与模块化设计方法既有联系又有区别。粗略地讲,逐步求精主要指一个程序的设计过程,而模块化设计主要指比较大的系统的设计过程。

此外,面对“软件危机”,人们调查研究了软件生产的实际情况,逐步感到采用工程化的方法从事软件系统的研究和维护的必要性,于是与程序设计方法学密切相关的软件工程在1968年应运而生。软件工程的主要对象是大型软件。软件工程研究的内容主要包括:软件质量保证和质量评价;软件研制和维护的方法、工具、文档;用户界面的设计以及软件管理等。软件工程的最终目的是摆脱手工生产软件的状况,逐步实现软件研制和维护的自动化。

软件危机的主要表现:

1. 对软件开发成本和进度的估计常常很不准确。
实际成本比估计成本有可能高出一个数量级,实际进度比预期进度拖延几个月甚至几年的现象并不罕见。这种现象降低了开发组织的信誉。为赶进度和节约成本所采取的权宜之计往往又损害了软件产品的质量,从而不可避免地引起用户的不满。

2. 用户对“已完成的”软件系统不满意的现象经常发生。
软件开发人员常常在对用户需求只有模糊的了解,甚至对所要解决的问题还没有确切认识的情况下,就仓促上阵匆忙着手编写程序。软件开发人员和用户之间的交流往往很不充分,“闭门造车”必然导致最终产品不符合用户实际需要。

3. 软件产品的质量常常靠不住。
软件可靠性和质量保证的确切定量概念刚刚出现,软件质量保证技术(审查、复审和测试)还没有坚持不懈地应用到软件开发的全过程中,这些都会导致软件产品发生质量问题。

4. 软件常常是不可维护的。
程序中的错误很难改正,实际上不可能使这些程序适应新的硬件环境,也不能根据用户的需求在原有程序中增加新的功能。

5. 软件通常没有适当的文档资料。
软件不仅是程序,还应该有一整套文档资料。这些文档资料是在软件开发过程中产生出来的,而且应该是“最新的”(与代码完全一致)。缺乏文档必然给软件的开发和维护带来许多严重的困难和问题。

6. 软件成本在计算机系统总成本中所占比例逐年上升。
随着微电子技术的进步和生产自动化程度的提高,硬件成本逐年下降,然而软件开发需要大量的人力,软件成本随着通货膨胀以及软件规模和数量的不断扩大而逐年上升。美国在1995年的调查表明,软件成本大约已占计算机系统总成本的90%。

软件危机的出现,使得人们去寻找产生危机的内在原因,发现其原因可归纳为两方面,一方面是由软件生产本身存在着复杂性,另一方面却是与软件开发所使用的方法和技术有关。

软件工程正是为克服软件危机而提出的一种概念,并在实践中不断地探索它的原理,技术和方法。在此过程中,人们研究和借鉴了工程学的某些原理和方法,并形成了一门新的学科─软件工程学,但可惜的是时至今日人们并没有完全克服软件危机。

转自 中程在线信息产业培训网 http://www.itisedu.com/phrase/200603112323405.html

2008年3月1日星期六

The Humble Programmer by Edsger W. Dijkstra


As a result of a long sequence of coincidences I entered the programming profession officially on the first spring morning of 1952 and as far as I have been able to trace, I was the first Dutchman to do so in my country. In retrospect the most amazing thing was the slowness with which, at least in my part of the world, the programming profession emerged, a slowness which is now hard to believe. But I am grateful for two vivid recollections from that period that establish that slowness beyond any doubt.

After having programmed for some three years, I had a discussion with A. van Wijngaarden, who was then my boss at the Mathematical Centre in Amsterdam, a discussion for which I shall remain grateful to him as long as I live. The point was that I was supposed to study theoretical physics at the University of Leiden simultaneously, and as I found the two activities harder and harder to combine, I had to make up my mind, either to stop programming and become a real, respectable theoretical physicist, or to carry my study of physics to a formal completion only, with a minimum of effort, and to become....., yes what? A programmer? But was that a respectable profession? For after all, what was programming? Where was the sound body of knowledge that could support it as an intellectually respectable discipline? I remember quite vividly how I envied my hardware colleagues, who, when asked about their professional competence, could at least point out that they knew everything about vacuum tubes, amplifiers and the rest, whereas I felt that, when faced with that question, I would stand empty-handed. Full of misgivings I knocked on van Wijngaarden's office door, asking him whether I could "speak to him for a moment"; when I left his office a number of hours later, I was another person. For after having listened to my problems patiently, he agreed that up till that moment there was not much of a programming discipline, but then he went on to explain quietly that automatic computers were here to stay, that we were just at the beginning and could not I be one of the persons called to make programming a respectable discipline in the years to come? This was a turning point in my life and I completed my study of physics formally as quickly as I could. One moral of the above story is, of course, that we must be very careful when we give advice to younger people; sometimes they follow it!

Another two years later, in 1957, I married and Dutch marriage rites require you to state your profession and I stated that I was a programmer. But the municipal authorities of the town of Amsterdam did not accept it on the grounds that there was no such profession. And, believe it or not, but under the heading "profession" my marriage act shows the ridiculous entry "theoretical physicist"!

So much for the slowness with which I saw the programming profession emerge in my own country. Since then I have seen more of the world, and it is my general impression that in other countries, apart from a possible shift of dates, the growth pattern has been very much the same.

Let me try to capture the situation in those old days in a little bit more detail, in the hope of getting a better understanding of the situation today. While we pursue our analysis, we shall see how many common misunderstandings about the true nature of the programming task can be traced back to that now distant past.

The first automatic electronic computers were all unique, single-copy machines and they were all to be found in an environment with the exciting flavour of an experimental laboratory. Once the vision of the automatic computer was there, its realisation was a tremendous challenge to the electronic technology then available, and one thing is certain: we cannot deny the courage of the groups that decided to try and build such a fantastic piece of equipment. For fantastic pieces of equipment they were: in retrospect one can only wonder that those first machines worked at all, at least sometimes. The overwhelming problem was to get and keep the machine in working order. The preoccupation with the physical aspects of automatic computing is still reflected in the names of the older scientific societies in the field, such as the Association for Computing Machinery or the British Computer Society, names in which explicit reference is made to the physical equipment.

What about the poor programmer? Well, to tell the honest truth: he was hardly noticed. For one thing, the first machines were so bulky that you could hardly move them and besides that, they required such extensive maintenance that it was quite natural that the place where people tried to use the machine was the same laboratory where the machine had been developed. Secondly, his somewhat invisible work was without any glamour: you could show the machine to visitors and that was several orders of magnitude more spectacular than some sheets of coding. But most important of all, the programmer himself had a very modest view of his own work: his work derived all its significance from the existence of that wonderful machine. Because that was a unique machine, he knew only too well that his programs had only local significance and also, because it was patently obvious that this machine would have a limited lifetime, he knew that very little of his work would have a lasting value. Finally, there is yet another circumstance that had a profound influence on the programmer's attitude to his work: on the one hand, besides being unreliable, his machine was usually too slow and its memory was usually too small, i.e. he was faced with a pinching shoe, while on the other hand its usually somewhat queer order code would cater for the most unexpected constructions. And in those days many a clever programmer derived an immense intellectual satisfaction from the cunning tricks by means of which he contrived to squeeze the impossible into the constraints of his equipment.

Two opinions about programming date from those days. I mention them now, I shall return to them later. The one opinion was that a really competent programmer should be puzzle-minded and very fond of clever tricks; the other opinon was that programming was nothing more than optimizing the efficiency of the computational process, in one direction or the other.

The latter opinion was the result of the frequent circumstance that, indeed, the available equipment was a painfully pinching shoe, and in those days one often encountered the naive expectation that, once more powerful machines were available, programming would no longer be a problem, for then the struggle to push the machine to its limits would no longer be necessary and that was all what programming was about, wasn't it? But in the next decades something completely different happened: more powerful machines became available, not just an order of magnitude more powerful, even several orders of magnitude more powerful. But instead of finding ourselves in the state of eternal bliss of all progamming problems solved, we found ourselves up to our necks in the software crisis! How come?

There is a minor cause: in one or two respects modern machinery is basically more difficult to handle than the old machinery. Firstly, we have got the I/O interrupts, occurring at unpredictable and irreproducible moments; compared with the old sequential machine that pretended to be a fully deterministic automaton, this has been a dramatic change and many a systems programmer's grey hair bears witness to the fact that we should not talk lightly about the logical problems created by that feature. Secondly, we have got machines equipped with multi-level stores, presenting us problems of management strategy that, in spite of the extensive literature on the subject, still remain rather elusive. So much for the added complication due to structural changes of the actual machines.

But I called this a minor cause; the major cause is... that the machines have become several orders of magnitude more powerful! To put it quite bluntly: as long as there were no machines, programming was no problem at all; when we had a few weak computers, programming became a mild problem, and now we have gigantic computers, programming had become an equally gigantic problem. In this sense the electronic industry has not solved a single problem, it has only created them, it has created the problem of using its products. To put it in another way: as the power of available machines grew by a factor of more than a thousand, society's ambition to apply these machines grew in proportion, and it was the poor programmer who found his job in this exploded field of tension between ends and means. The increased power of the hardware, together with the perhaps even more dramatic increase in its reliability, made solutions feasible that the programmer had not dared to dream about a few years before. And now, a few years later, he had to dream about them and, even worse, he had to transform such dreams into reality! Is it a wonder that we found ourselves in a software crisis? No, certainly not, and as you may guess, it was even predicted well in advance; but the trouble with minor prophets, of course, is that it is only five years later that you really know that they had been right.

Then, in the mid-sixties, something terrible happened: the computers of the so-called third generation made their appearance. The official literature tells us that their price/performance ratio has been one of the major design objectives. But if you take as "performance" the duty cycle of the machine's various components, little will prevent you from ending up with a design in which the major part of your performance goal is reached by internal housekeeping activities of doubtful necessity. And if your definition of price is the price to be paid for the hardware, little will prevent you from ending up wth a design that is terribly hard to program for: for instance the order code might be such as to enforce, either upon the progrmmer or upon the system, early binding decisions presenting conflicts that really cannot be resolved. And to a large extent these unpleasant possibilities seem to have become reality.

When these machines were announced and their functional specifications became known, quite a few among us must have become quite miserable; at least I was. It was only reasonable to expect that such machines would flood the computing community, and it was therefore all the more important that their design should be as sound as possible. But the design embodied such serious flaws that I felt that with a single stroke the progress of computing science had been retarded by at least ten years: it was then that I had the blackest week in the whole of my professional life. Perhaps the most saddening thing now is that, even after all those years of frustrating experience, still so many people honestly believe that some law of nature tells us that machines have to be that way. They silence their doubts by observing how many of these machines have been sold, and derive from that observation the false sense of security that, after all, the design cannot have been that bad. But upon closer inspection, that line of defense has the same convincing strength as the argument that cigarette smoking must be healthy because so many people do it.

It is in this connection that I regret that it is not customary for scientific journals in the computing area to publish reviews of newly announced computers in much the same way as we review scientific publications: to review machines would be at least as important. And here I have a confession to make: in the early sixties I wrote such a review with the intention of submitting it to the CACM, but in spite of the fact that the few colleagues to whom the text was sent for their advice, urged me all to do so, I did not dare to do it, fearing that the difficulties either for myself or for the editorial board would prove to be too great. This suppression was an act of cowardice on my side for which I blame myself more and more. The difficulties I foresaw were a consequence of the absence of generally accepted criteria, and although I was convinced of the validity of the criteria I had chosen to apply, I feared that my review would be refused or discarded as "a matter of personal taste". I still think that such reviews would be extremely useful and I am longing to see them appear, for their accepted appearance would be a sure sign of maturity of the computing community.

The reason that I have paid the above attention to the hardware scene is because I have the feeling that one of the most important aspects of any computing tool is its influence on the thinking habits of those that try to use it, and because I have reasons to believe that that influence is many times stronger than is commonly assumed. Let us now switch our attention to the software scene.

Here the diversity has been so large that I must confine myself to a few stepping stones. I am painfully aware of the arbitrariness of my choice and I beg you not to draw any conclusions with regard to my appreciation of the many efforts that will remain unmentioned.

In the beginning there was the EDSAC in Cambridge, England, and I think it quite impressive that right from the start the notion of a subroutine library played a central role in the design of that machine and of the way in which it should be used. It is now nearly 25 years later and the computing scene has changed dramatically, but the notion of basic software is still with us, and the notion of the closed subroutine is still one of the key concepts in programming. We should recognise the closed subroutines as one of the greatest software inventions; it has survived three generations of computers and it will survive a few more, because it caters for the implementation of one of our basic patterns of abstraction. Regrettably enough, its importance has been underestimated in the design of the third generation computers, in which the great number of explicitly named registers of the arithmetic unit implies a large overhead on the subroutine mechanism. But even that did not kill the concept of the subroutine, and we can only pray that the mutation won't prove to be hereditary.

The second major development on the software scene that I would like to mention is the birth of FORTRAN. At that time this was a project of great temerity and the people responsible for it deserve our great admiration. It would be absolutely unfair to blame them for shortcomings that only became apparent after a decade or so of extensive usage: groups with a successful look-ahead of ten years are quite rare! In retrospect we must rate FORTRAN as a successful coding technique, but with very few effective aids to conception, aids which are now so urgently needed that time has come to consider it out of date. The sooner we can forget that FORTRAN has ever existed, the better, for as a vehicle of thought it is no longer adequate: it wastes our brainpower, is too risky and therefore too expensive to use. FORTRAN's tragic fate has been its wide acceptance, mentally chaining thousands and thousands of programmers to our past mistakes. I pray daily that more of my fellow-programmers may find the means of freeing themselves from the curse of compatibility.

The third project I would not like to leave unmentioned is LISP, a fascinating enterprise of a completely different nature. With a few very basic principles at its foundation, it has shown a remarkable stability. Besides that, LISP has been the carrier for a considerable number of in a sense our most sophisticated computer applications. LISP has jokingly been described as "the most intelligent way to misuse a computer". I think that description a great compliment because it transmits the full flavour of liberation: it has assisted a number of our most gifted fellow humans in thinking previously impossible thoughts.

The fourth project to be mentioned is ALGOL 60. While up to the present day FORTRAN programmers still tend to understand their programming language in terms of the specific implementation they are working with —hence the prevalence of octal and hexadecimal dumps—, while the definition of LISP is still a curious mixture of what the language means and how the mechanism works, the famous Report on the Algorithmic Language ALGOL 60 is the fruit of a genuine effort to carry abstraction a vital step further and to define a programming language in an implementation-independent way. One could argue that in this respect its authors have been so successful that they have created serious doubts as to whether it could be implemented at all! The report gloriously demonstrated the power of the formal method BNF, now fairly known as Backus-Naur-Form, and the power of carefully phrased English, a least when used by someone as brilliant as Peter Naur. I think that it is fair to say that only very few documents as short as this have had an equally profound influence on the computing community. The ease with which in later years the names ALGOL and ALGOL-like have been used, as an unprotected trade mark, to lend some of its glory to a number of sometimes hardly related younger projects, is a somewhat shocking compliment to its standing. The strength of BNF as a defining device is responsible for what I regard as one of the weaknesses of the language: an over-elaborate and not too systematic syntax could now be crammed into the confines of very few pages. With a device as powerful as BNF, the Report on the Algorithmic Language ALGOL 60 should have been much shorter. Besides that I am getting very doubtful about ALGOL 60's parameter mechanism: it allows the programmer so much combinatorial freedom, that its confident use requires a strong discipline from the programmer. Besides expensive to implement it seems dangerous to use.

Finally, although the subject is not a pleasant one, I must mention PL/1, a programming language for which the defining documentation is of a frightening size and complexity. Using PL/1 must be like flying a plane with 7000 buttons, switches and handles to manipulate in the cockpit. I absolutely fail to see how we can keep our growing programs firmly within our intellectual grip when by its sheer baroqueness the programming language —our basic tool, mind you!— already escapes our intellectual control. And if I have to describe the influence PL/1 can have on its users, the closest metaphor that comes to my mind is that of a drug. I remember from a symposium on higher level programming language a lecture given in defense of PL/1 by a man who described himself as one of its devoted users. But within a one-hour lecture in praise of PL/1. he managed to ask for the addition of about fifty new "features", little supposing that the main source of his problems could very well be that it contained already far too many "features". The speaker displayed all the depressing symptoms of addiction, reduced as he was to the state of mental stagnation in which he could only ask for more, more, more... When FORTRAN has been called an infantile disorder, full PL/1, with its growth characteristics of a dangerous tumor, could turn out to be a fatal disease.

So much for the past. But there is no point in making mistakes unless thereafter we are able to learn from them. As a matter of fact, I think that we have learned so much, that within a few years programming can be an activity vastly different from what it has been up till now, so different that we had better prepare ourselves for the shock. Let me sketch for you one of the posssible futures. At first sight, this vision of programming in perhaps already the near future may strike you as utterly fantastic. Let me therefore also add the considerations that might lead one to the conclusion that this vision could be a very real possibility.

The vision is that, well before the seventies have run to completion, we shall be able to design and implement the kind of systems that are now straining our programming ability, at the expense of only a few percent in man-years of what they cost us now, and that besides that, these systems will be virtually free of bugs. These two improvements go hand in hand. In the latter respect software seems to be different from many other products, where as a rule a higher quality implies a higher price. Those who want really reliable software will discover that they must find means of avoiding the majority of bugs to start with, and as a result the programming process will become cheaper. If you want more effective programmers, you will discover that they should not waste their time debugging, they should not introduce the bugs to start with. In other words: both goals point to the same change.

Such a drastic change in such a short period of time would be a revolution, and to all persons that base their expectations for the future on smooth extrapolation of the recent past —appealing to some unwritten laws of social and cultural inertia— the chance that this drastic change will take place must seem negligible. But we all know that sometimes revolutions do take place! And what are the chances for this one?

There seem to be three major conditions that must be fulfilled. The world at large must recognize the need for the change; secondly the economic need for it must be sufficiently strong; and, thirdly, the change must be technically feasible. Let me discuss these three conditions in the above order.

With respect to the recognition of the need for greater reliability of software, I expect no disagreement anymore. Only a few years ago this was different: to talk about a software crisis was blasphemy. The turning point was the Conference on Software Engineering in Garmisch, October 1968, a conference that created a sensation as there occured the first open admission of the software crisis. And by now it is generally recognized that the design of any large sophisticated system is going to be a very difficult job, and whenever one meets people responsible for such undertakings, one finds them very much concerned about the reliability issue, and rightly so. In short, our first condition seems to be satisfied.

Now for the economic need. Nowadays one often encounters the opinion that in the sixties programming has been an overpaid profession, and that in the coming years programmer salaries may be expected to go down. Usually this opinion is expressed in connection with the recession, but it could be a symptom of something different and quite healthy, viz. that perhaps the programmers of the past decade have not done so good a job as they should have done. Society is getting dissatisfied with the performance of programmers and of their products. But there is another factor of much greater weight. In the present situation it is quite usual that for a specific system, the price to be paid for the development of the software is of the same order of magnitude as the price of the hardware needed, and society more or less accepts that. But hardware manufacturers tell us that in the next decade hardware prices can be expected to drop with a factor of ten. If software development were to continue to be the same clumsy and expensive process as it is now, things would get completely out of balance. You cannot expect society to accept this, and therefore we must learn to program an order of magnitude more effectively. To put it in another way: as long as machines were the largest item on the budget, the programming profession could get away with its clumsy techniques, but that umbrella will fold rapidly. In short, also our second condition seems to be satisfied.

And now the third condition: is it technically feasible? I think it might and I shall give you six arguments in support of that opinion.

A study of program structure had revealed that programs —even alternative programs for the same task and with the same mathematical content— can differ tremendously in their intellectual manageability. A number of rules have been discovered, violation of which will either seriously impair or totally destroy the intellectual manageability of the program. These rules are of two kinds. Those of the first kind are easily imposed mechanically, viz. by a suitably chosen programming language. Examples are the exclusion of goto-statements and of procedures with more than one output parameter. For those of the second kind I at least —but that may be due to lack of competence on my side— see no way of imposing them mechanically, as it seems to need some sort of automatic theorem prover for which I have no existence proof. Therefore, for the time being and perhaps forever, the rules of the second kind present themselves as elements of discipline required from the programmer. Some of the rules I have in mind are so clear that they can be taught and that there never needs to be an argument as to whether a given program violates them or not. Examples are the requirements that no loop should be written down without providing a proof for termination nor without stating the relation whose invariance will not be destroyed by the execution of the repeatable statement.

I now suggest that we confine ourselves to the design and implementation of intellectually manageable programs. If someone fears that this restriction is so severe that we cannot live with it, I can reassure him: the class of intellectually manageable programs is still sufficiently rich to contain many very realistic programs for any problem capable of algorithmic solution. We must not forget that it is not our business to make programs, it is our business to design classes of computations that will display a desired behaviour. The suggestion of confining ourselves to intellectually manageable programs is the basis for the first two of my announced six arguments.

Argument one is that, as the programmer only needs to consider intellectually manageable programs, the alternatives he is choosing between are much, much easier to cope with.

Argument two is that, as soon as we have decided to restrict ourselves to the subset of the intellectually manageable programs, we have achieved, once and for all, a drastic reduction of the solution space to be considered. And this argument is distinct from argument one.

Argument three is based on the constructive approach to the problem of program correctness. Today a usual technique is to make a program and then to test it. But: program testing can be a very effective way to show the presence of bugs, but is hopelessly inadequate for showing their absence. The only effective way to raise the confidence level of a program significantly is to give a convincing proof of its correctness. But one should not first make the program and then prove its correctness, because then the requirement of providing the proof would only increase the poor programmer's burden. On the contrary: the programmer should let correctness proof and program grow hand in hand. Argument three is essentially based on the following observation. If one first asks oneself what the structure of a convincing proof would be and, having found this, then constructs a program satisfying this proof's requirements, then these correctness concerns turn out to be a very effective heuristic guidance. By definition this approach is only applicable when we restrict ourselves to intellectually manageable programs, but it provides us with effective means for finding a satisfactory one among these.

Argument four has to do with the way in which the amount of intellectual effort needed to design a program depends on the program length. It has been suggested that there is some kind of law of nature telling us that the amount of intellectual effort needed grows with the square of program length. But, thank goodness, no one has been able to prove this law. And this is because it need not be true. We all know that the only mental tool by means of which a very finite piece of reasoning can cover a myriad cases is called "abstraction"; as a result the effective exploitation of his powers of abstraction must be regarded as one of the most vital activities of a competent programmer. In this connection it might be worth-while to point out that the purpose of abstracting is not to be vague, but to create a new semantic level in which one can be absolutely precise. Of course I have tried to find a fundamental cause that would prevent our abstraction mechanisms from being sufficiently effective. But no matter how hard I tried, I did not find such a cause. As a result I tend to the assumption —up till now not disproved by experience— that by suitable application of our powers of abstraction, the intellectual effort needed to conceive or to understand a program need not grow more than proportional to program length. But a by-product of these investigations may be of much greater practical significance, and is, in fact, the basis of my fourth argument. The by-product was the identification of a number of patterns of abstraction that play a vital role in the whole process of composing programs. Enough is now known about these patterns of abstraction that you could devote a lecture to about each of them. What the familiarity and conscious knowledge of these patterns of abstraction imply dawned upon me when I realized that, had they been common knowledge fifteen years ago, the step from BNF to syntax-directed compilers, for instance, could have taken a few minutes instead of a few years. Therefore I present our recent knowledge of vital abstraction patterns as the fourth argument.

Now for the fifth argument. It has to do with the influence of the tool we are trying to use upon our own thinking habits. I observe a cultural tradition, which in all probability has its roots in the Renaissance, to ignore this influence, to regard the human mind as the supreme and autonomous master of its artefacts. But if I start to analyse the thinking habits of myself and of my fellow human beings, I come, whether I like it or not, to a completely different conclusion, viz. that the tools we are trying to use and the language or notation we are using to express or record our thoughts, are the major factors determining what we can think or express at all! The analysis of the influence that programming languages have on the thinking habits of its users, and the recognition that, by now, brainpower is by far our scarcest resource, they together give us a new collection of yardsticks for comparing the relative merits of various programming languages. The competent programmer is fully aware of the strictly limited size of his own skull; therefore he approaches the programming task in full humility, and among other things he avoids clever tricks like the plague. In the case of a well-known conversational programming language I have been told from various sides that as soon as a programming community is equipped with a terminal for it, a specific phenomenon occurs that even has a well-established name: it is called "the one-liners". It takes one of two different forms: one programmer places a one-line program on the desk of another and either he proudly tells what it does and adds the question "Can you code this in less symbols?" —as if this were of any conceptual relevance!— or he just asks "Guess what it does!". From this observation we must conclude that this language as a tool is an open invitation for clever tricks; and while exactly this may be the explanation for some of its appeal, viz. to those who like to show how clever they are, I am sorry, but I must regard this as one of the most damning things that can be said about a programming language. Another lesson we should have learned from the recent past is that the development of "richer" or "more powerful" programming languages was a mistake in the sense that these baroque monstrosities, these conglomerations of idiosyncrasies, are really unmanageable, both mechanically and mentally. I see a great future for very systematic and very modest programming languages. When I say "modest", I mean that, for instance, not only ALGOL 60's "for clause", but even FORTRAN's "DO loop" may find themselves thrown out as being too baroque. I have run a a little programming experiment with really experienced volunteers, but something quite unintended and quite unexpected turned up. None of my volunteers found the obvious and most elegant solution. Upon closer analysis this turned out to have a common source: their notion of repetition was so tightly connected to the idea of an associated controlled variable to be stepped up, that they were mentally blocked from seeing the obvious. Their solutions were less efficient, needlessly hard to understand, and it took them a very long time to find them. It was a revealing, but also shocking experience for me. Finally, in one respect one hopes that tomorrow's programming languages will differ greatly from what we are used to now: to a much greater extent than hitherto they should invite us to reflect in the structure of what we write down all abstractions needed to cope conceptually with the complexity of what we are designing. So much for the greater adequacy of our future tools, which was the basis of the fifth argument.

As an aside I would like to insert a warning to those who identify the difficulty of the programming task with the struggle against the inadequacies of our current tools, because they might conclude that, once our tools will be much more adequate, programming will no longer be a problem. Programming will remain very difficult, because once we have freed ourselves from the circumstantial cumbersomeness, we will find ourselves free to tackle the problems that are now well beyond our programming capacity.

You can quarrel with my sixth argument, for it is not so easy to collect experimental evidence for its support, a fact that will not prevent me from believing in its validity. Up till now I have not mentioned the word "hierarchy", but I think that it is fair to say that this is a key concept for all systems embodying a nicely factored solution. I could even go one step further and make an article of faith out of it, viz. that the only problems we can really solve in a satisfactory manner are those that finally admit a nicely factored solution. At first sight this view of human limitations may strike you as a rather depressing view of our predicament, but I don't feel it that way, on the contrary! The best way to learn to live with our limitations is to know them. By the time that we are sufficiently modest to try factored solutions only, because the other efforts escape our intellectual grip, we shall do our utmost best to avoid all those interfaces impairing our ability to factor the system in a helpful way. And I cannot but expect that this will repeatedly lead to the discovery that an initially untractable problem can be factored after all. Anyone who has seen how the majority of the troubles of the compiling phase called "code generation" can be tracked down to funny properties of the order code, will know a simple example of the kind of things I have in mind. The wider applicability of nicely factored solutions is my sixth and last argument for the technical feasibiilty of the revolution that might take place in the current decade.

In principle I leave it to you to decide for yourself how much weight you are going to give to my considerations, knowing only too well that I can force no one else to share my beliefs. As each serious revolution, it will provoke violent opposition and one can ask oneself where to expect the conservative forces trying to counteract such a development. I don't expect them primarily in big business, not even in the computer business; I expect them rather in the educational institutions that provide today's training and in those conservative groups of computer users that think their old programs so important that they don't think it worth-while to rewrite and improve them. In this connection it is sad to observe that on many a university campus the choice of the central computing facility has too often been determined by the demands of a few established but expensive applications with a disregard of the question how many thousands of "small users" that are willing to write their own programs were going to suffer from this choice. Too often, for instance, high-energy physics seems to have blackmailed the scientific community with the price of its remaining experimental equipment. The easiest answer, of course, is a flat denial of the technical feasibility, but I am afraid that you need pretty strong arguments for that. No reassurance, alas, can be obtained from the remark that the intellectual ceiling of today's average programmer will prevent the revolution from taking place: with others programming so much more effectively, he is liable to be edged out of the picture anyway.

There may also be political impediments. Even if we know how to educate tomorrow's professional programmer, it is not certain that the society we are living in will allow us to do so. The first effect of teaching a methodology —rather than disseminating knowledge— is that of enhancing the capacities of the already capable, thus magnifying the difference in intelligence. In a society in which the educational system is used as an instrument for the establishment of a homogenized culture, in which the cream is prevented from rising to the top, the education of competent programmers could be politically impalatable.

Let me conclude. Automatic computers have now been with us for a quarter of a century. They have had a great impact on our society in their capacity of tools, but in that capacity their influence will be but a ripple on the surface of our culture, compared with the much more profound influence they will have in their capacity of intellectual challenge without precedent in the cultural history of mankind. Hierarchical systems seem to have the property that something considered as an undivided entity on one level, is considered as a composite object on the next lower level of greater detail; as a result the natural grain of space or time that is applicable at each level decreases by an order of magnitude when we shift our attention from one level to the next lower one. We understand walls in terms of bricks, bricks in terms of crystals, crystals in terms of molecules etc. As a result the number of levels that can be distinguished meaningfully in a hierarchical system is kind of proportional to the logarithm of the ratio between the largest and the smallest grain, and therefore, unless this ratio is very large, we cannot expect many levels. In computer programming our basic building block has an associated time grain of less than a microsecond, but our program may take hours of computation time. I do not know of any other technology covering a ratio of 1010 or more: the computer, by virtue of its fantastic speed, seems to be the first to provide us with an environment where highly hierarchical artefacts are both possible and necessary. This challenge, viz. the confrontation with the programming task, is so unique that this novel experience can teach us a lot about ourselves. It should deepen our understanding of the processes of design and creation, it should give us better control over the task of organizing our thoughts. If it did not do so, to my taste we should not deserve the computer at all!

It has already taught us a few lessons, and the one I have chosen to stress in this talk is the following. We shall do a much better programming job, provided that we approach the task with a full appreciation of its tremendous difficulty, provided that we stick to modest and elegant programming languages, provided that we respect the intrinsic limitations of the human mind and approach the task as Very Humble Programmers.