2.1 编程语言的世界
大家知道世界上最早的编程语言是什么吗?一般认为是 1954 年开始开发的 FORTRAN 语言。
然而,仔细想想看,到底什么才叫编程语言?如果将对机器的控制也看成是编写“程序”的话,那么编程的起源便可以追溯到杰卡德织机上面所使用的打孔纸带(图 1)。
图 1 杰卡德织机的示意图
1801 年,正值工业革命期间,杰卡德织机的发明使得提花编织的图案可以通过“程序”来自动完成。从前在各个家庭中也出现了自动纺织机,用于家庭作坊式的自动纺织生产,而杰卡德织机则相当于是这些家庭纺织机的放大版。我想那些自动纺织机应该也可以通过类似打孔纸带的东西来输入图案,当然,最近的年轻人恐怕都没有亲眼见过纺织机吧。
这种用打孔纸带来控制机器的想法,对各个领域都产生了影响。例如在英国从事通用计算机研发的查尔斯·巴贝奇,就在自制的“分析机”上用打孔纸带来输入控制程序。1遗憾的是,由于资金和其他一些问题,巴贝奇在生前未能将他的分析机制造出来。
1 查尔斯 • 巴贝奇(Charles Babbage,1791—1871),是英国数学家,计算机先驱,可编程计算机的发明者。分析机(Analytical Engine)是巴贝奇设计的一种机械式十进制通用计算机,虽然由于种种原因,它并未被真正制造出来,但其设计理念可以说是 100 年后电子通用计算机的先驱。
不过,分析机的设计已经完成,用于分析机的程序也作为文档保留了下来。协助开发这些程序的,是英国诗人拜伦之女爱达·洛夫莱斯2,据说她和巴贝奇是师兄妹关系。如果不算分析机的设计者巴贝奇,那么世界上第一位程序员实际上是一位女性。为了纪念她,还有一种编程语言以她的名字 Ada 命名3。
2 爱达 • 洛夫莱斯(Ada Lovelace,1815—1852),原名奥古斯塔 • 爱达 • 拜伦,洛夫莱斯是丈夫威廉 • 洛夫莱斯伯爵的姓氏。
3 这里指的是 1980 年由美国军方设计的一种名为 Ada 的编程语言。
说点题外话,在现在的编程界中,女性人数很少这一点是有目共睹的,尤其是在开源相关的活动上,男女比例达到 100 比 1 也不稀奇。其实,在计算机早期时代,有记录表明人们大都认为程序员应该是女性从事的工作,也许是人们将程序员和当时电话交换机的接线员(从业者中也是女性居多)看成是同一类型的工作吧。
在被称为世界上第一台计算机的 ENIAC 4(1946 年)中,程序不是用打孔纸带,而是通过接电线的方式来输入的,我总觉得这是一种倒退。
4 ENIAC(Electronic Numerical Integrator And Computer,电子数值积分计算机),是由美国宾夕法尼亚大学穆尔电气工程学院设计建造的电子计算机,于 1946 年公布,为美国陆军的弹道研究实验室服务。
不过,无论是接电线,还是打孔纸带,都不大可能实现复杂的程序,真正的程序恐怕还要等到存储程序式计算机出现之后。一般认为,世界上第一台存储程序式电子计算机,是 1949 年出现的 EDSAC 5。
5 EDSAC(Electronic Delay Storage Automatic Calculator,电子延迟存储自动计算器),是英国剑桥大学数学实验室的莫里斯 • 威尔克斯(Maurice Wilkes,1913—2010)教授及其团队于 1946 年开始设计建造的电子计算机,1949 年 5 月 6 日正式运行。
到了这个时候,所谓的“机器语言”就算正式问世了。当时的计算机程序都是用机器语言来编写的。那个时候不要说是编译器,连汇编器都还没发明出来呢,因此使用机器语言也是理所当然的事。
说到底,机器语言就是一串数字,将计算的步骤从指令表中查出对应的机器语言编码,再人工写成数列,这个工作可不容易。或者说,以前的人虽然没有意识到,但从我们现代人的角度来看,这种辛苦简直是难以置信。比如说,把引导程序的机器语言数列整个背下来,每次启动的时候手工输入进去;将机器语言指令表全部背下来,不用在纸上打草稿就能直接输入机器语言指令并正确运行——“古代”的程序员们留下了无数的光辉事迹(或者是传说),那时候的人们真是太伟大了。
然而有一天,有一个人忽然想到,查表这种工作本来应该是计算机最擅长的,那么让计算机自己来做不就好了吗?于是,人们用更加容易记忆的指令(助记符)来代替数值,并开发了一种能够自动生成机器语言的程序,这就是汇编器。
汇编器是用来解释“汇编语言”的程序,汇编语言中所使用的助记符,和计算机指令是一一对应的关系。早期的计算机主要还是用于数值计算,因此数学才是主宰。在数学的世界中,数百年来传承下来的“语言”就是算式,因此用接近算式的形式来编写计算机指令就显得相当方便。随后,FORTRAN 于 1954 年问世了。FORTRAN 这个名字的意思是:
FORmula TRANslator 算式 翻译器也就是说,编程语言是由编程者根据自己的需要发明出来的。早期的计算机,由于性能不足、运算成本高,因此编写和维护程序都被看成是非人的工作,而编程语言正是其开始摆脱非人性的象征。
其实,由助记符自动生成机器语言的汇编器,以及由人类较易懂的算式型语句生成机器语言的编译器,当时都被认为是革新性的技术,被称为“自动编程”。此外,编译器开发技术的研究甚至被视为人工智能研究的一部分。
被历史埋没的先驱
一般大家都认为 ENIAC 是世界上第一台计算机,而 FORTRAN 是世界上第一个编程语言,然而,事实果真如此吗?我觉得有必要刨根问底一番。
实际上,如果仔细查阅一下计算机的历史,还是会发现一些不同观点的。
首先,世界上第一台计算机,其实应该是“阿塔纳索夫 - 贝瑞计算机”(Atanasoff-Berry Computer,简称 ABC),这台计算机的测试机完成于 1939 年,远比 ENIAC 要早。而且,ABC 在数值的表现方法上采用了现在广泛使用的二进制计算(ENIAC 为十进制计算),这也是 ABC 的其中一个先进之处。
ENIAC 甚至都不能算作是世界上第二台计算机。当时在第二次世界大战中与美国敌对的德国,开发出了一台用于土木工程计算的计算机 Z3 6。这台计算机完成于 1941 年,和 ABC 一样,在数值表现上也采用了二进制。和由电子管组成的 ABC 和 ENIAC 不同,Z3 是继电器式计算机。遗憾的是,Z3 在 1944 年柏林轰炸中被毁。
6 在 Z3 之前当然还开发了 Z1 和 Z2,但它们是用于特定用途的计算机,而并非通用计算机。(原书注)
那么,编程语言方面又如何呢?通过查阅资料发现,开发 Z3 的德国工程师康拉德·楚泽,于 1942 年至 1945 年间开发了一种名为 Plankalkül 的编程语言,比 FORTRAN 早了将近 10 年。7 然而,Plankalkül 只是被设计出来,而没有被正式发表,而且用于该编程语言的编译器也没有被开发出来。
7 康拉德 • 楚泽(Konrad Zuse,1910—1995),是一位德国土木工程师,计算机先驱。Plankalkül 被认为是世界上第一个非冯 • 诺依曼型高级编程语言,它的名称在德语中的意思是“用于规划的正式系统”(Formal system for planning)。
Plankalkül 的设计直到 1972 年才被正式发表,而到第一个用于该语言的编译器正式实现,已经是 1998 年的事了。因此,如果论完整开发并能工作的编程语言,FORTRAN 作为最古老编程语言的地位还是无人能够撼动。
Plankalkül 由于种种原因被淹没在历史的长河中,因此它对后世的编程语言几乎没有产生影响,但是,它却考虑了如赋值语句、子程序、条件判断、循环、浮点小数计算、数组、拥有层次结构的结构体、断言、异常处理、目标搜寻等功能,其中一些甚至连 10 年后出现的 FORTRAN 都不具备,可见其先进性着实令人惊叹。
P1 max3 (V0[:8.0],V1[:8.0],V2[:8.0]) => R0[:8.0] max(V0[:8.0],V1[:8.0]) => Z1[:8.0] max(Z1[:8.0],V2[:8.0]) => R0[:8.0] END P2 max (V0[:8.0],V1[:8.0]) => R0[:8.0] V0[:8.0] => Z1[:8.0] (Z1[:8.0] < V1[:8.0]) -> V1[:8.0] => Z1[:8.0] Z1[:8.0] => R0[:8.0] END图 2 用 Plankalkül 编写的程序
图 2 给出了一段 Plankalkül 程序,其中定义了用于对两个参数进行比较的子程序 max,以及利用这个子程序进而对三个参数进行比较的子程序 max3。其中所有的运算过程都被表示为“计算 => 结果保存位置”这样的形式,相当有意思。
编程语言的历史
在 FORTRAN 之后,20 世纪 50 年代末至 80 年代初,各种各样的编程语言如雨后春笋般相继出现,从而成就了一个编程语言研究飞速发展的鼎盛时期。
在这里,我们暂且抛开那些现在还健在的主流编程语言,而是将目光放在一些最近不怎么听说了,但却值得品味的编程语言上,并借此简单介绍一下编程语言的历史。
1. FORTRAN
话说回来,一开始我们还是先来讲讲 FORTRAN 这个主流语言吧。
FORTRAN 作为实质上的世界第一种编程语言,在数值计算领域建立了霸主地位。需要数值计算功能的物理学家等研究人员并不关心编程,对他们来说,计算速度有多快,是否能充分利用过去的成果,这两点才是最重要的。
从结果来看,FORTRAN 非常重视和过去的程序之间的兼容性,为此,它保留了一些现在已经几乎不再使用的编码风格,其中最典型的一个例子,就是 FORTRAN 的语法中所包含的下面这个难以置信的规则。
在程序中空格没有意义
这个规则的意思是,空格只是为了易读才加上去的,而编译器在编译程序时会把空格全部去掉。这样的语法,以现代编程语言的习惯来看简直是匪夷所思。为什么这样说呢?例如:
DO 100 I = 1,10这样一行程序,它的语法和 DO 语句的语法是一致的,程序的意思是在循环中将从 1 到 10 的值依次赋值给变量 I,当循环结束之后跳转到行号为 100 的语句,到这里看起来也没有什么问题。
不过,如果我将 DO 语句中“1,10”中的逗号错打成句点的话,会发生什么事呢?也就是说:
DO 100 I = 1.10我们之前已经说过,FORTRAN 会忽略所有的空格,那么这个语句就会被转换为:
DO100I=1.10这样一来,由于这个语句不符合 DO 语句的语法,因此编译器会将这个语句理解为“将浮点小数 1.10 赋值给变量 DO100I”,编号为 100 的那一行则被彻底忽略掉了。也就是说,本来程序的意图是要执行一个循环,现在却变成了一个赋值语句,循环也就无效了。这可以说是在语法分析相关研究相对落后的年代设计出来的编程语言所特有的悲剧。
另一方面,追求计算速度的人们依然在使用着 FORTRAN,并且积累了一些十分大胆的优化技术。例如,为了最大限度利用超级计算机中装备的向量处理器,而自己改写 DO 循环以实现向量化等。
最近的超级计算机也几乎不再使用向量型结构,因此也很少会遇到必须使用 FORTRAN 的情况,使用超级计算机的研究人员更多地开始使用 Java 和 C++ 之类的语言。不过,即便如此,FORTRAN 也并没有要消亡的迹象。
此外,FORTRAN 本身也在不断进化,在最新版本中还实现了如编程抽象化、数据结构分配等功能,和其他先进编程语言相比毫不逊色。
2. COBOL
COBOL 这个名称是 COmmon Business Orientd Language(面向商业的通用语言)的缩写,相对于面向科学计算的 FORTRAN,COBOL 是作为面向商务计算而出现的编程语言,于 1959 年被开发出来。
基于下面的推理:
o 由于是面向商业计算,因此不需要太多的算式
o 对于从事商业活动的“一般大众”来说,采用更接近日常表达方式(英语)的语法,比采用数学算式更容易理解
COBOL 采用了类似英语的语法,但对于我这个日本人来说,把:
AB = A * B写成:
MULTIPLY A BY B GIVING AB.真的更容易理解吗?恐怕要打一个大大的问号。
不过,由于积累了大量过去的数据,COBOL 直到 21 世纪的今天依然健在。虽然在计算机类杂志中已经看不到关于 COBOL 的文章,但也有说法称,COBOL 依然是现在使用最广泛的一种编程语言。
实际上,在我供职的网络应用通信研究所中,有一半的技术人员是用 Ruby 来进行软件开发,剩下一半则是使用 COBOL。不过我们用的硬件只是普通的 PC 服务器,操作系统用的是 Linux,其他事务监视器等工具用的也都是开源软件,这倒是还挺少见的。
那么,COBOL 到底好不好用呢?从像我这样没用过 COBOL 的人的角度来看,一定会觉得“这啥啊,跟别的程序差别太大了吧”,不过 COBOL 的技术人员会主张说“如果要实现把账簿里的数字从右边移到左边,即便在现在 COBOL 也是效率最高的”。即使排除他们已经用惯了 COBOL 这个因素,这个评价还是相当值得回味的。
COBOL 也在不断进化,据说在最新版本中还增加了面向对象的功能。
3. Lisp
Lisp 和 FORTRAN、COBOL 一起并称为“古代编程语言三巨头”(我命名的),它的名字意思是:
LISt Processor 表 处理器Lisp 是一种特殊的编程语言,因为它原本并不是作为编程语言,而是作为一种数学计算模型来设计的。Lisp 的设计者约翰·麦卡锡设计了一种以 Lambda 演算为基础的“图灵完全”8的计算模型,而 Lisp(的起源)则是为了描述这一模型而设计出来的。
8 约翰 • 麦卡锡(John McCarthy,1927—2011)是美国著名的计算机科学家,于 1971 年因人工智能方面的贡献获得图灵奖。Lambda 演算(Lambda calculus)是由阿隆佐 • 邱奇(Alonzo Church,1903—1995)提出的一种十分简洁的计算模型,是 Lisp 等函数型编程语言的理论基础。它不同于通用图灵机的计算模式,但它是图灵完全的。图灵完全(Turing complete)是指一种计算模型拥有和通用图灵机相同的计算能力,即一种计算模型可以实现对目前已知所有算法的描述。目前大部分通用编程语言(如 C、Java 等)都是图灵完全的。
不过,麦卡锡并没有想到将其作为一种计算机语言来使用,直到他实验室的一位研究生史帝芬·罗素用 IBM 704 机器语言实现了描述计算模型的万能函数 eval(求值函数),Lisp 才作为一种编程语言正式诞生。9
9 IBM 704 是由 IBM 公司于 1954 年推出的内置浮点计算功能的大型计算机,FORTRAN 和 Lisp 等编程语言都是在 IBM 704 上开发出来的。
此外,Lisp 是早期能够对数值以外的值进行处理的语言。相对于 FORTRAN 和 COBOL 这样只能进行数值计算的语言来说,Lisp 擅长于表结构这样的非数值型处理,因此,Lisp 被广泛用于人工智能这样的领域中。
在 20 世纪 60 年代,一般人还不会为了计算以外的目的使用计算机,因此 Lisp 主要在大学和研究所等地方传播开来。
现在的计算机对字符串处理和通信等非数值处理已经成为主流,而 Lisp 则是这样一个时代的先驱者。此外,因 Java 而广为人知的垃圾回收和异常处理等机制,实际上最初是由 Lisp 发明的。因此,Lisp 对现在的计算机科学基础的构筑做出了极大的贡献,尽管使用者寥寥,但现在它依然是用于实用系统开发的现役编程语言。
4. SNOBOL
早期的 Lisp 所能够处理的数据只有表和符号,并不擅长处理字符串。而一种专门用于字符串处理的语言,在历史上扮演了重要的角色,它就是 SNOBOL(发音近似 Snow Ball)。SNOBOL 的名字意思是:
StriNg Oriented symBOlic Language 字符串 面向 符号化 语言其中 N 和 BO 取的位置好像很奇怪,不过别太在意就是了。SNOBOL 的革新性在于它是以模板(Pattern)为中心来进行字符串处理的,可以说是现在的 AWK、Perl 和 Ruby 等语言的祖先。不过 SNOBOL 的字符串模板并不是正则表达式,而是采用了类似 BNF(巴科斯 - 诺尔范式)10的写法。
10 巴科斯 - 诺尔范式(Backus-Naur Form),是由约翰 • 巴科斯(John Backus,1924—2007)和彼得 • 诺尔(Peter Naur,1928— )首先引入的用来描述计算机语言语法的符号集,是一种描述上下文无关文法的语言。
由这样的编程语言所积累的经验,可以说是加快了计算机向数值计算以外的方向发展的步伐。
图 3 展示了一段用 SNOBOL 的模板匹配来解 N 皇后问题11的程序。当模板匹配时跳转到一个明确标明的标签,这样的风格现在已经不怎么见得到了。
11 N 皇后问题(N-Queen Problem),最初为 8 皇后问题,即如何在国际象棋棋盘(8×8)上摆放 8 个皇后,使得它们彼此都无法直接吃掉对方(即彼此不能处于同一直线或斜线上)。8 皇后问题共有 12 个独立解(将旋转、对称解作为同一解的话),而后来便由此引申出 N 皇后问题(此时皇后个数为 N,且棋盘大小同时为 N×N)。
* N queens problem, a string oriented version to * demonstrate the power of pattern matching. * A numerically oriented version will run faster than this. N = 5 NM1 = N - 1; NP1 = N + 1; NSZ = N * NP1; &STLIMIT = 10 ** 9; &ANCHOR = 1 DEFINE('SOLVE(B)I') * This pattern tests if the first queen attacks any of the others: TEST = BREAK('Q') 'Q' (ARBNO(LEN(N) '-') LEN(N) 'Q' + | ARBNO(LEN(NP1) '-') LEN(NP1) 'Q' + | ARBNO(LEN(NM1) '-') LEN(NM1) 'Q') P = LEN(NM1) . X LEN(1); L = 'Q' DUPL('-',NM1) ' ' SOLVE() :(END) SOLVE EQ(SIZE(B),NSZ) :S(PRINT) * Add another row with a queen: B = L B LOOP I = LT(I,N) I + 1 :F(RETURN) B TEST :S(NEXT) SOLVE(B) * Try queen in next square: NEXT B P = '-' X :(LOOP) PRINT SOLUTION = SOLUTION + 1 OUTPUT = 'Solution number ' SOLUTION ' is:' PRTLOOP B LEN(NP1) . OUTPUT = :S(PRTLOOP)F(RETURN)图 3 用 SNOBOL 来解 N 皇后问题的程序
5. 数学性语言
刚才已经讲过,Lisp 是由数学而诞生的编程语言,不过这样的语言可不止 Lisp 一个。
例如,Prolog 就是一个以一阶谓词逻辑为基础的编程语言。20 世纪 80 年代,日本政府主导的第五代计算机计划12中就采用了 Prolog(准确地说应该是以 Prolog 为基础的逻辑型编程语言),使得其名声大噪,但当第五代计算机计划逐渐淡出人们的视线之后,Prolog 也随之销声匿迹了。不过,逻辑型编程语言所具备的“联合”(Unification)匹配模式,也在最近备受关注的函数型编程语言中被继承了下来。
12 第五代计算机计划,是由日本通商产业省(现经济产业省)主导的一项国家开发计划,目的是开发“可高速执行谓词逻辑推理的并行逻辑计算机及其操作系统”。整个计划从 1982 年启动,共耗时 10 年,花费 570 亿日元,于 1992 年宣布结束,并称“已达到预期目标”。
以数学为基础的编程语言中,还有另外一个派系被称为函数型编程语言,例如 ML、 Haskell 等就属于这一类。这一类数学性语言,比起机器的处理方式,更倾向于直接表达要表达的概念,也就是说相对于 How(如何实现),更倾向于通过 What(想要什么)来表达问题。这样可以不被机器的处理方式所左右,将问题抽象地表达出来,这是一种非常先进的特性。关于这一点,在后面“未来的编程语言”一节中还会进行详细介绍。
6. 主流语言
众人皆知的那些编程语言就没必要特地在这里介绍了吧。作为系统描述语言的 C 和 C++、作为面向商务的语言而如日中天的 Java,以及在 Web 领域中十分热门的 Ruby、Perl、Python、PHP 等脚本语言,都属于主流语言。
这些语言在成长过程中都吸收了过去一些语言的优点,如 Java 的设计借鉴了 C++、 Smalltalk 和 Lisp 的优点,而 Ruby 则是在吸收过去语言优点的基础上加以独自发展而形成的语言。
编程语言的进化方向
从过去编程语言的历史中,我们可以看出编程语言是在不断试错的过程中发展起来的。有很多编程语言已经消亡,仅仅在历史中留下了它们的名字,但其中所包含的思想,却被后来的语言以不同的形式吸取和借鉴。
例如,SNOBOL 的字符串处理功能,可以说是现代脚本语言基本功能的祖先。此外,20 世纪 70 年代由美国麻省理工学院(MIT)开发的一种名为 CLU 13的语言中迭代器(Iterator)的概念,也被 Ruby 以代码块(Block)的形式继承了下来。
13 CLU 是由 MIT 的芭芭拉 • 利斯科夫(Barbara Liskov,1939— )所开发的语言,利斯科夫于 2008 年获得图灵奖。(原书注)
从编程语言的进化过程来看,一个显著的关键词就是“抽象化”。抽象化就是提供一个抽象的概念,使用者即便不具备关于其内部详细情况的知识,也能够对其进行运用。由于不必了解其内部的情况,因此也被称为“黑箱化”。
一些古老的编程语言,例如 BASIC 就没有实现充分的抽象化。虽然它提供了用于过程共享的子程序这个概念,但是子程序只能通过编号来调用,而且不能传递参数。由于“赋予名称”是抽象化的重要部分,所以说它的抽象化是不充分的。近代的编程语言中,都可以为一系列过程(程序)赋予相应的名称。
然而,仅仅将过程进行抽象化还远远不够。几乎所有的过程都需要进行一定的输入输出操作,而并不是与数据无关的。因此,在下一个阶段中,对数据进行黑箱化就显得非常重要。刚才我们提到的 CLU,就是数据抽象化出现早期的一种语言。
在数据抽象化的延长线上,就自然而然产生了面向对象编程的概念。所谓对象,就是抽象化的数据本身,因此面向对象和数据抽象化之间仅仅隔了薄薄的一张纸。在现在的 21 世纪编程语言中,面向对象已经是常识了,最近几乎所有的语言都或多或少地提供了面向对象的能力。当然,其中也有一些语言故意不提供对面向对象的支持14。
14 例如,下一节中将要介绍的由保罗 • 格雷厄姆所设计的 Arc 语言,就(至少在其内置功能中)不支持面向对象,据保罗说,是有意这样设计的。(原书注)
随着抽象化的不断深入,程序员即便不去关心内部的详细情况,也可以编写出程序。人类一次所能掌握的概念数量是有限的,有说法称,大部分人一次只能驾驭 7±2 个左右的概念。这样一来,如果能够让问题的处理方式更加抽象,也就可以解决更复杂的问题。
受摩尔定律的影响,社会对于软件也提出了越来越高的要求。人类社会越来越依赖计算机,因此就需要开发出更多更可靠、更便宜的软件。
在讲述软件开发的一本名著《人月神话》中,作者弗雷德里克·布鲁克斯写道:15
15 《人月神话——软件项目管理之道》(The Mythical Man-Month: Essays on Software Engineering)首次出版于 1975 年,并于 1995 年进行了扩充和再版。弗雷德里克 • 布鲁克斯(Frederick P. Brooks, Jr.,1931— )是美国的软件工程师,曾主持开发了 IBM 的 OS/360 操作系统,于 1999 年获得图灵奖。
无论使用什么编程语言,生产一条基本语句所需要的工数几乎是一定的。
也就是说,如果要描述同样的算法,A 语言需要 1000 行,B 语言只需要 10 行的话,只要采用 B 语言生产效率就可以提高 100 倍。
可能有人会觉得“这太扯了吧”。打个比方,用 Java 和 Ruby 描述同样的算法,语句行数相差 2 倍多也不稀奇,如果是汇编语言和 Ruby 相比的话,也许能产生 100 倍甚至 1000 倍的差距。
能产生这样的生产效率差异,正是抽象化的力量。抽象度高的编程语言不必描述详细过程,从而可以用简短的代码达到目的。和抽象化程度的差异相比,变量名称、有没有指定数据类型之类的都只能算是误差级别的差异而已。
未来的编程语言
从编程语言的进化这个视角来看,其实最近并没有什么大的动作。现在使用最广泛的编程语言几乎都是 10 多年前出现的,即便是比较新的 Java 和 Ruby 也是诞生于 20 世纪 90 年代后半期,距离现在也已经是 15 年之前的事了。也许可以说,现在正是编程语言进化的好时机吧。
最近,受到 CPU 多核化等因素的影响,Erlang 16这种并行处理语言受到了不少关注。不过 Erlang 早在 1987 年就诞生了,也并不是什么新东西,有点失望呀。
16 Erlang 是由瑞典电信公司爱立信(Ericsson)旗下计算机科学研究室所开发的一种编程语言,发布于 1987 年,并于 1998 年实现开源。
那么,未来的编程语言究竟会变成什么样呢?
美国风险投资家、Lisp 启蒙家、作家保罗·格雷厄姆在其《一百年后的编程语言》17一文中想象了 100 年后可能会出现的编程语言,并提议将他的观点应用到现在的编程语言中。
17 保罗 • 格雷厄姆(Paul Graham,1964— )是美国风险投资家、计算机科学作家。《一百年后的编程语言》(The Hundred-Year Language)一文收录于保罗 • 格雷厄姆的文集《黑客与画家》一书中,人民邮电出版社 2011 年 4 月出版,阮一峰译。
他主张,100 年后的编程语言进化的主线,应该以少量公理为基础的“拥有最小最简洁核心的语言”。在现有编程语言中,最具有这一特征的莫过于他最喜欢的 Lisp 了。所以说,他的主张实际上就是说,Lisp 才是 100 年后编程语言的进化方向。
唔,像我这样的小人物要跟他叫板好像也挺不自量力的,不过我还是认为,对于未来,应该基于从过去到现在的变化方向,并在其延长线上做出预测。当然,将来也许会发生一些无法预料的状况,从而大幅扭转之前的前进方向,不过这样的事情从定义来说本来就是无法预测的,你非要预测它,本质上也是毫无意义的。
作为一个编程语言御宅族,通过反观过去半个世纪以来编程语言的进化方向,我认为编程语言绝对不会按照保罗·格雷厄姆所说,向着“小而干净”的方向来进化。现在的编程语言,无论是功能上还是语法上都已经不是那样单纯了,虽然也曾经有人努力尝试将这些语言变得更小更简单,但包括保罗·格雷厄姆自己所设计的 Arc 18在内,都决不能算是成功的尝试。
18 Arc 语言是 Lisp 的方言之一,由保罗 • 格雷厄姆与罗伯特 • 泰潘 • 莫里斯(Robert Tappan Morris,1965— )共同设计,于 2008 年首次发布。
在我看来,编程语言的进化动机,不是工具和语言本身的简化,而是将通过这些工具和语言所得到的结果(解决方案)更简洁地表达出来。近半个世纪以来,编程语言不断提供愈发高度的抽象化特性,也正是为了达到这个目的。因此我们可以很自然地认为,这种趋势在将来也应该会继续保持。
基于上述观点,如果要我来预测 100 年后编程语言的样子,我认为应该会是下面三种情况的其中之一:
1. 变化不大。编程语言的写法从 20 世纪 80 年代开始就几乎没有什么进化,今后即便出现新的写法,也只是现有写法的变形而已。(从发展上来看,是比较悲观的未来)
2. 使用编程语言来编程这个行为本身不存在了。人类可以通过和计算机对话(大概是用自然语言)来查询和处理信息。(类似《星际迷航》中的世界,对于编程语言家来说是比较失落的未来)
3. 发明了采用更高抽象度写法的编程语言。这种语言在现在很难想象,不过应该是比现在更加强调 What,而对于如何解决问题的 How 部分的细节,则不再需要人类去过问。(难以预测的未来)
当然,上面的预测也只不过仅仅是预测而已,有可能与未来的实际情况大相径庭,或者说,与实际大相径庭的可能性比较大吧。不过话说回来,100 年后我也已经不在这个世上了,这不是白操心嘛。
20 年后的编程语言
通过对 100 年后的预测,我们明白了“预测 100 年后的事情是非常困难的”。想想看,100 年前连飞机还没有民用化呢,100 年后我已经可以坐在飞机上舒舒服服地写这本书的稿子了,这足以说明,要想象社会的变化是相当困难的。
那么,更近一点的未来又怎么样呢?比如说 20 年后。20 年前,日本刚刚改年号为平成19,现在和那个时候相比,印象中社会应该没有发生非常极端的变化。计算机的性能等方面确实有了长足的进步,不过发展趋势还是连续的,并非无法预测。对于 20 年后的未来,我想应该可以根据现在的发展趋势来做出判断。
19 除了公元纪年外,日本人还普遍习惯使用年号纪年。和中国封建王朝时期一样,年号一般是随天皇的更换而进行更迭。1989 年,明仁天皇即位,改年号为平成,因此 2012 年是平成 24 年。在平成之前的上一个年号是昭和。
个人认为,这么短的时间内,编程语言本身应该不会发生多大的变化。实际上,现在使用的很多语言,在 20 年前就已经存在的。因此我预计,20 年后的语言,应该是在分布处理(多台计算机协作处理)和并行处理(多个 CPU 协作处理)功能上进行强化,使得开发者不需要特 别花心思就能够使用这些功能。
之所以要关注分布处理和并行处理,是因为今后个人也可以通过云计算的形式使用到比现 在更多的计算机,而随着每台计算机的 CPU 多核化,就相当于安装了更多的 CPU,这些情形都 是很容易想象的。
不过,我认为现在的线程、RPC(Remote Procedure Call,远程过程调用)等显式地使用分布处理和并行处理的形式,早晚会遇到瓶颈。当核心数量超过数千个的时候,显式指定就变得毫无意义了,调试起来也会变得非常痛苦。我期待在 20 年后,能够出现突破这种局限的技术,即无需显式操作就可以实现分布处理和并行处理。
学生们的想象
几年前,我曾经在母校筑波大学开展过一次关于编程语言的集中讲座。在讲座中我给学生们出了“想象一下 20 年后的编程语言”这样一个题目,并在讲座最后一天提交报告。很有意思的是,大多数学生并没有做出我上面所说的关于分布处理和并行处理之类的技术性预测,而是提出了诸如“让编程变得更简单的语言”、“希望用自然语言来控制计算机”之类的想象。通过这些答案,似乎可以看出他们平常为了完成编程作业而被折磨得何等痛苦。
不过,这样的答案中,也许也蕴含着真理。近年来,编程语言似乎越来越难以脱离 IDE(Integrated Development Environment,集成开发环境)而单独拿出来说了。对于 Ruby 也总有人问“没有 IDE 吗?”之类的问题,当然,好消息是最近 Eclipse 和 NetBeans 已经支持 Ruby 了。
有点跑题了。总之,未来的编程语言可能不会像过去的编程语言那样,让语言本身单独存在,而是和编辑器、调试器、性能分析器等开发工具相互配合,以达到提高整体生产效率的目的。话说,那不就是 Smalltalk 20吗?
20 Smalltalk 正是一种考虑了“与编辑器、调试器、性能分析器等开发工具相互配合”而设计的语言。过去它并不能算是成功的,但随着技术的进步,其理念获得了越来越多的用武之地,或许真能卷土重来也未可知。(原书注)
唔,历史是否会重演呢?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论