千字回顾从五十年代到互联网早期的程序设计语言
Contents
这篇文章是作为后续一篇讨论程序员细分工作的文章的前提,我们之所以先从程序语言的历史说起,是因为当我们将程序员分为各种岗位讨论时,这些岗位其实都起源于某个源头,并从中分化,如果我们想对现实进行一个较为深入的探讨,就不得不对历史有所回顾。
50年代和60年代
共认的第一台电子计算机埃尼阿克ENIAC于1945年制成,尽管在50年代末期,电子管的制造技术可以让电子管计算机稳定运行成百上千小时,但能够规模化批量化制造出能够更加稳定运行并减少维护成本的计算机,还要等到50年代末期发明了MOS晶体管,从此计算机进入了晶体管计算机时代。在这之前,电子计算机仅仅存在于少数科研院所或者军事机构,对应的机器指令和汇编语言也并没有统一的规范。虽然少数科研人员已经认识到了机器码以及汇编语言编程的低效,并尝试开发更为高级的语言,但总体来讲,这是一个蛮荒富有生机却又割裂的时代,这个时代有很多编程语言昙花一现,仅在历史中留下很浅的足迹。
Fortran
出现的第一个重要语言是Fortran,最初由IBM在1954年开始设计,于1957年完成了第一个可用的编译器。Fortran的开发目标是由科学家和工程人员用来书写数值计算密集程序,相较于使用汇编语言,Fortran的语法更为接近现代编程语言,而且方便程序员输入计算公式。正如上文所言,Fortran诞生于一个计算机硬件开始能够保证稳定运行的时代节点,这和Fortran的使用友好程度导致了一种流行和事实上的标准。虽然在这个时代并不只有IBM一家制造商,但它的竞争对手基本上都为自己的设备实现了Fortran编译器,使得同样的Fortran程序能够在不同厂商制造的设备上运行。Fortran贴近硬件的优化能力,使得它目前仍在作为一线计算语言而在很多超算服务器中运行,或者作为软件包而被第三方语言调用。
LISP
作为人工智能的鼻祖之一,在1958年,John John McCarthy看到了IBM的计算机在AI上的潜力,当然Fortran并不能满足他的编程需求,于是他便设计了LISP语言,它仅仅使用简单的符号和列表表达式语法就有了极为丰富的表达能力,设计和同时代的其他语言也有着很大不同,更接近于数学而不是计算机硬件。对于这种语言我不想赘述,因为既没有足够的能力,也会影响本文的可读性。我只想说曾经在某一个时期,或者说很久的时期内,每一个计算机专业的学生都会尝试以学会某种LISP语言的变种为傲,然而大部分人在踏入门槛前就止步了。它对后续的程序语言设计和发展有着极为深远的影响,比如垃圾回收机制GC就是在LISP中被实现。
ALGOL
同一时期,计算机科学家们也在致力于发明一种新的统一的用于交流的语言,即ALGOL(源自ALGOrithmic Language 的缩写),它的第一个版本ALGOL 58 和 后继版本ALGOL 60引进了许多现今再熟悉不过的但在当时是全新的概念:如块,词法作用域,递归等,它在编程语言设计和发展演化中有着巨大的影响力,标志着程序设计语言成为一门独立的科学学科。然而ALGOL语言的重点过于学术化,在于清楚的描述算法和程序的结构化,以至于直到第三个版本ALGOL68才包含了输入输出IO的内置实现,这比Fortran晚了整整十年。在早期的算法和程序语言教科书中,经常可以看到ALGOL语言的例子,除此以外的领域,ALGOL的应用并不常见。
COBOL
同一时期还有另外一种计算需求,不同于各种物理科学计算,也不同于计算机科学家们的理论需求,商业数据处理领域同样需要一种高级语言,这种需求遍布于军方、金融机构和政府机构等。 当然,这些行业的编程人员需要更低的门槛,因为相比于科学计算工作者和计算机科学家而言,他们对数学和各种符号知之甚少。于是简单易用,尽量使用英文单词的,对业务数据批量处理友好的COBOL就诞生了。设计目标自然导致了COBOL和主流计算机学界的脱节,其对后世的编程语言影响,相对于其海量的既有代码而言,便显得微不足道了。自从COBOL60/61/63/65的快速迭代和68/74的稳定成型及修改后,再之后的任何版本变动都带来了兼容性问题,最后一次规范的修订在2023年。至今仍有许多COBOL代码在国外的一些核心系统中运行,毕竟对于很多关键节点来说,程序“能跑就行”,虽然在“千年虫”中,COBOL作为核心业务系统的重要实现语言,成为了灾难爆发的中心。
BASIC及PASCAL
我们在上面提到了几门对于专业工作者适用的语言,但是计算机语言发展到此时仍然没有一门语言适合教学或者较为复杂的工程,Fortran偏重计算,ALGOL太学术,LISP太数学,COBOL太随意,于是在60年代中后期,两种新的语言被基于ALGOL语言设计和实现了出来,即BASIC和PASCAL。 同样在60年代,由于计算机性能的提升和硬件成本的降低,将更为普及的计算资源分给多个用户使用便成为了一种需求,这就导致了操作系统的诞生。之前的语言经过编译后直接在硬件运行,而新的潮流是经过操作系统的硬件抽象后对资源和程序进行调度,这种趋势一直延续到家用计算机的诞生。(这篇文章中我们刻意避免讨论操作系统历史和个人电脑发展史) BASIC被设计为一种易于教学的语言,首次实现于1964年。BASIC虽然不能说成动态语言的鼻祖,但它具有了很多现代动态语言的特性,比如带有实时反馈的交互式操作,更易懂的英文保留字和语法,对硬件和操作系统的抽象等等。 PASCAL则于1970年发行,其重要目标之一就是弥合FORTRAN和COBOL之间的鸿沟,填补这部分之间编程需求的空白。PASCAL引进了一些概念和机制,使程序员(在ALGOL的标量和数组之上)能定义他们自己的复杂(结构化)数据类型,也使建立诸如lists、trees和graphs这样的动态和递归数据结构更容易。 随着70年代中期个人电脑的兴起,BASIC和PASCAL开始进入更多人的视野,在这个过程中,BASIC的背后是Microsoft公司的身影,PASCAL则有着Borland公司的支持,伴随着面向对象设计的概念引入和GUI的开发,它们在九十年代分别有了新的后继者,对于BASIC,是Visual Basic,即VB,对于PASCAL,是Delphi。
70年代
Smalltalk
1970年代,施乐帕克研究中心Xerox PARC设计了一种新的面向对象OOP语言,Smalltalk。随着这门语言的演进,现代程序员所熟知的一些OOP概念,如类Class和实例Instance等都开始出现,并影响了后续的很多语言,如Java,Python,Ruby等。 Xerox PARC还有其他一些耳熟能详的发明,如激光打印机,图形交互界面GUI,鼠标,以太网等。除了OOP机制,Smalltalk还引入了MVC(Model-View-Controller)的概念,这些都深入影响了图形交互界面GUI的变革。Xerox PARC这种以用户为中心和跨学科合作的思想,或许也是Smalltalk诞生并对后续程序语言发展有重大影响的原因之一。
C和C++
操作系统的需求在上文中简略提到过,其提供了提供基本硬件管理、软件调度和资源监控(我们在现代的编程工作中仍能看到不同层级资源抽象的同类工作),一个重要的节点即是IBM的OS/360系统,被用于其生产的大型机系统,其1966年发布的第一版使用汇编语言编写。作者Fred Brooks以此开发过程中的经验写作了一本著名的软件工程书籍《人月神话》,这本书即使在现在也有着极强的现实意义和参考价值,实际上,它一点也没有落后,甚至可以说,它的价值从未被认真对待。 在稍后的几年内,贝尔实验室的Dennis Ritchie和Ken Thompson用汇编语言编写了第一版的UNIX操作系统,适用于另外一个计算机制造商DEC的小型机PDP-7,在接下来几年内对其进行了改造,并于1971年共同设计和发明了C语言。1973年两人用C语言重写了Unix,形成第三版UNIX,并深刻影响了目前几乎占据所有企业级服务器市场的Linux系统。 随着免费版本及商业版本UNIX的推广,C语言也得到了进一步的推广,这种推广在两方面体现,一面是作为系统编程工具,因为这是除了汇编语言以外的第一种能高效访问系统硬件比如内存的高级语言,对于硬件的抽象很“薄”,并且又有很强的移植性。另一方面,正因为这种特性,导致C语言可以高效的利用硬件资源,能够作为一种计算语言,从而成为了Fortran的竞争对手,并被其他一些语言作为计算库进行引进,比如科学计算软件Matlab和符号数学计算软件Mathematica。80年代初期,Bjarne Stroustrup为了适应大型软件开发的需求,在C语言的基础上增加了面向对象特性,从而设计出了C++。作为开发复杂的大型高性能软件的优秀武器,C++被广泛使用至今,无论是桌面端还是服务器端,还是从游戏行业到模拟计算行业。
80年代
Perl
除了上文中提到的C++和Matlab/Mathematica,以及在国内从未流行过但在国外的军用系统及关键设施中流行的ADA,80年代或许最值得关注的语言便是Perl了。 Perl使用了很多语言学的思维,相比C或者PASCAL这样的“高级”语言而言,Perl语言直接提供泛型变量、动态数组、Hash表等更加便捷的编程元素和灵活的特性,并且还从其他多种语言中借鉴了语法规则,从而提供了许多冗余语法,即著名的Perl编程哲学,“There’s more than one way to do it”,这导致很多Perl代码容易进入一种难于理解和维护的状态,以至于有一个著名的段子“修改一段Perl代码还不如重写它”。Perl程序员可以忽略计算机内部资料存储、类型、处理方法、运算规则、甚至内存越界等等的细节,而将思考中心放在所需要的程序逻辑上。此时的计算机性能提升正处在摩尔定律的预言范畴之内,因而Perl这门虽然运行效率较低,但是开发快速,抽象度高,能方便处理文本和系统编程的语言便有了生存之地。 Perl在90年代极为流行,甚至有了一个著名的软件仓库CPAN(The Comprehensive Perl Archive Network),直到遇到了Python,其编程准则为“There should be one and preferably only one obvious way to do it.”
90年代
Python
Python的开发始于90年代,类似于Perl,Python集合了很多语言的特点,但不同于Perl,其简洁的哲学和OOP的特性,其程序更为容易理解,因而除了快速开发外,同样适合开发较为大型的项目。同时Python “Batteries Included"的设计哲学还意味着,Python自身包含大量的常用功能库,并不需要额外安装第三方软件,这进一步实践了“There should be one and preferably only one obvious way to do it.”。这种哲学一直持续到现在,比如2004年发布的矩阵数学计算库Numpy和现今著名的机器学习组件Pytorch,都在某种或深或浅的程度上成为了一种标准。
Java
随着90年代互联网的兴起,在连续多次变换Java语言的发展方向后,作者James Gosling最终瞄准了浏览器,很早期的互联网使用者或许还记得浏览器里安装Java插件的日子,然而数年之后,Java就在桌面浏览器的斗争中败给了Flash和JavaScript,却在互联网服务器后端流行开来,并成为了至今企业级互联网服务的主流研发语言。当然,同期的PHP作为Web服务端开发语言,更为简单容易上手,曾经在此领域比Java更为流行,并维持了相当久的优势。 Java是一门极其优秀的工程语言,其OOP特性使得其可以设计大型且复杂的软件,类似于C++,然而其所拥有的垃圾回收GC机制又使其在开发使用中更为安全,虚拟机的设计又使得跨平台迁移和性能优化成为可能,这就降低了程序开发者的心智负担,进一步降低了大型复杂软件开发的门槛。
JavaScript
20世纪末的一个经典商战就是网景公司Netscape和微软公司Microsoft的互联网浏览器大战,最终网景败退,并由Mozilla Firefox继承了Netscape Navigator。作为浏览器中执行的脚本语言,网景公司设计的JavaScript的命名完全是蹭了Java的热度,而作为其在20世纪末对手的微软公司Microsoft则不甘示弱推出了功能相近却并不完全兼容的JScript,这给当时的浏览器脚本开发人员带来了相当大的麻烦。这种浏览器实现的不兼容性,使得JavaScript在接近十年的发展停滞后,随着Google Chrome浏览器及智能大屏设备的流行,以2009年12月发布的ECMAScript 5标准为重要的节点,走向和谐发展的快速轨道。
其他,21世纪和未来
在上面的文字里,除了偶尔提到的一些语言,我们还忽略了很多其他语言,例如:
用于并发网络通信的Erlang 统计学内被广泛使用的R 早期Windows平台专用,现在可以跨平台的适合复杂软件开发的C# 更为轻量的脚本语言,适合作为胶水或者游戏脚本的Lua 几乎成为大数据开发标准语言的Scala 拥有快速开发Web网站框架的Ruby 适合开发高性能网络服务的Go 内存安全的C++替代者Rust 背靠巨头和平台的Swift及Dart 为了解决前端大型工程痛点的Typescript 还有很多其他语言
并不是说这些语言的重要程度一定比不上前文提到的语言,只是从更早的历史角度来看,个人认为前述的语言在早期历史中留下了更为特殊的印记。至于未来会不会有新的语言被设计出来,从生态的角度来说很困难,毕竟从零开始构建程序生态并使其流行的工作量很大,但是在AI的加持下,我们不能排除一种可能,即会有一门更自然的编程语言,能在硬件,业务和开发人员三者之间打造出更为高效的桥梁。
硬件的利用,抽象能力,可维护性,商业公司的推动,行业的发展,历史的演进,影响了每一门编程语言的命运。