程序设计语言,又叫做编程语言,是构成计算机程序的一组规范化的语法规则。本文回顾了程序设计语言的历史,对程序设计语言的发展主要趋势一一列举并做出了评论,最后对程序设计语言的未来提出了展望。
历史概略
众所周知,在今天,程序设计语言与电子计算机是分不开的。然而,程序设计语言的历史似乎比电子计算机还要久远。其实,早在计算机发明100年前,便出现了史上第一位程序员——Ada Lovelace。她在1842年至1843年间花费了九个月,将意大利数学家Luigi Menabrea关于查尔斯•巴贝奇新发表机器分析机的回忆录翻译完成[1]。她于那篇文章后面附加了一个用分析机计算伯努利数方法的细节,被部分历史学家认为是世界上第一个计算机程序。
在20世纪40年代,人们制造了第一台电子计算机ENIAC,并由此产生了相应的机器语言。从此以后,程序设计语言大致经历了从机器语言,到汇编语言,在到高级语言的发展阶段。
1955年,第一个高级语言Fortran出现,同一时代的高级语言还有LISP、COBOL、ALGOL 58、BASIC等。高级语言是高度封装了的编程语言,它的出现使人们摆脱了汇编语言与机器语言的繁琐,进而可以从更高的层面上思考与编写程序。这些语言引入了循环、子程序、区块等概念,开创了结构化程序设计的先河。另一重大成就是巴克斯范式(BNF)的引入。这种上下文无关文法可以用数学化的精确符号描述编程语言的语法与规则,它被从此以后几乎所有的编程语言所采纳。
20世纪60、70年代,程序设计语言有了重大发展。其中富有标志性的主要有Simula、C、Smalltalk、Prolog、ML等语言。其中,Simula与Smalltalk引入了面向对象的概念;C是经久不衰的一种系统程序设计语言,至今仍可与众多编程语言逐鹿中原;Prolog是史上第一个逻辑编程语言;而ML则是继承自LISP,成为了静态类型函数式编程语言的先驱;这些语言都各自演展出自己的家族分支,现今多数现代编程语言的祖先都可以追朔他们其中至少一个以上。
1990年代,人类进入了互联网时代,相应的产生了Java、PHP、Python、Lua等语言。这些语言大多运行于虚拟机之上,支持面向对象,并具有垃圾收集功能。它们还配有集成开发环境,大大提高了开发小路。这一时期,专为互联网设计的动态脚本语言例如JavaScript等也蓬勃发展,它们使得今天的互联网丰富多彩。
进入21世纪,程序设计语言持续发展,F#、Scala、Clojure、Go等都是人们为提高开发效率所做出的努力。这一时期程序设计语言,大多具有元编程、面向方面程序设计、面向移动终端开发、静态执行绪检查等特性。
发展趋势
纵观近30年以来的计算机发展史,我们发现外部存储器大小已经提高了10万倍,内存大小提高了近1万倍,CPU计算速度也有1000倍的提升[2]。然而,编程语言的发展相对于硬件来说却显得相当缓慢。30年间,程序设计语言本身提出了诸如面向对象等新的范式,但人们所做的大多数努力都用在了构建框架与工具上。随便打开一款现代IDE,你会发现代码提示、自动重构、调试器等无数强大的功能;而现代编程语言(例如C#、Java、Python)的库,相对于几十年前的C语言来说,更是有上千倍的增长。
从编程语言发展伊始,抽象级别的提高一直是一个显著的趋势。从一开始的机器语言,到汇编语言;从结构化编程语言,到面向对象语言,再到多范式程序设计语言。人们不断地使编程语言的表现力得到提高,让程序员可以用更少的代码,完成更多的工作。我们有理由相信,在未来相当长的时间内,抽象层次的提高仍是程序设计语言发展的一大主要趋势。
“多范式程序设计语言”也是一个越来越明显的趋势。在程序设计语言发展最初阶段,一门程序设计语言按照主要编程范式,往往可以被归类为面向过程式的、面向对象式的、函数式的等;按照运行方式分,可分为编译式和解释式的;而若按照变量行为,还可以分为动态的与静态的等。然而,随着C++、C#等语言的出现,传统分类之间的界限逐渐变得模糊。一门支持面向对象的语言,多半也渗透着函数式编程的思想;传统意义上的静态语言中也逐渐加入了反射等动态成分;而即时编译(JIT)技术的出现,更是使编译与解释的区别渐趋于无。其实,在过去几十年间各种语言的相互对抗中,人们逐渐发现了没有一种单一类型的语言是完美的,因此现代的编程语言无一例外地同时加入了若干种类编程语言的元素,这就是所谓的多范式编程语言。
另一个令人看好的趋势是声明式编程。编程语言大体可分为命令式与声明式两种,目前,我们使用的大多数编程语言是命令式语言,例如C、Java、Python等。命令式编程即为告诉计算机如何做某事,而声明式却是告诉计算机做什么事。例如我们若希望计算机打印出1000以内的所有素数,若使用命令式编程,则我们需要用循环逐个枚举1000以内的自然数,然后再对于每个自然数,用一次循环判断其是否为素数,若是则输出;但若使用声明式编程,则只需告诉计算机“从1000以内自然数中挑选出素数并输出”就行了。可见命令式的代码中更多的体现了计算机如何处理与解决问题,而不是问题是什么。用命令式的方式编程,不仅使得代码变得冗长无味,更会造成问题更高层的信息的丢失,使计算机对于代码的优化无从下手。
领域特定语言(DSL)是将命令式编程转为声明式的一种方法。DSL是指转为某一方面而设计的计算机语言。例如网页中使用的CSS,数据库中使用的SQL还有文本处理中使用的正则表达式等。这些语言由于针对于特定领域,通常能够减除底层细节,从较高层面上描述领域内的问题。常见的DSL大略分为两类,一类被称为外部DSL,这些DSL一般拥有独立的文件和运行环境,它们通常被其他的程序解释执行,例如前文所列举的SQL、正则表达式等。另一类则被称为内部DSL,它们其实只是编程语言内部的一组API。内部DSL通常依赖于编程语言强大的语法规则,让使用者用起来“像”另一种特定领域的语言。一些内部DSL利用面向对象的特性创造出一组流畅接口,例如Web开发中使用的jQuery库、.NET中的Linq;另一些则用到了程序设计语言自带的元编程能力,构建出更加透明的使用体验,例如Ruby On Rails等。
1965年摩尔提出了摩尔定律:集成电路上可容纳的电晶体数目,约每隔18个月便会增加一倍[3]。有人预计定律将持续到至少2015年或2020年。然而,2010年国际半导体技术发展路线图的更新增长已经放缓在2013年年底,之后的时间里晶体管数量密度预计只会每三年翻一番[4]。但有一点是显然的,那就是处理器的时钟频率已经停止了增长(甚至近两年来略有下降)。那多余的晶体管到哪里去了呢?人们想到了代替方案,那就是制造多核处理器。有人说,从某种意义上来讲,依靠计算机性能提升获得免费午餐的时代已经一去不复返。为了充分利用目前处理器所提供的计算能力,我们必须主动换一种写程序的方式。
从传统的串行程序设计转换到并行程序设计是困难的,这需要对程序设计语言本身进行必要的变革。在并行编程方面,传统上人们拥有Thread、Mutex、Lock、Memory Barrier、CAS等工具。但由于这些API过于靠近底层,实际环境中并不方便使用,还容易引发优先级倒置、死锁等问题。所谓并行计算的本质,不过是将一个逻辑上的任务分解为若干个可以同时执行的任务块。在分解任务的思想基础上,人们将任务这一概念直接实现于编程语言API中,于是便有了并行循环、任务池等概念。而针对传统并行程序中,由于共享内存区域和锁引发的访问冲突、死锁等问题,一些编程语言如Erlang、Go等则引入了线程间的消息机制,通过改变线程间共享数据的方式,在一定程度将这些问题予以解决。
总结
“没有银弹”,正如IBM大型机之父佛瑞德·布鲁克斯所说[5],软件开发有其自身的复杂性,我们无法指望任何一门编程语言可以在十年以内使开发效率提高十倍。现在没有,未来也不会有任何一门程序设计语言是完美的。但编程语言会不断地发展变化,新的语言及特性会被不断提出,它们势必将逐渐改变我们的生活。
参考文献
[1]: Wikipedia, History of programming languages
[2]: Anders Hejlsberg, Trends and future directions in programming languages, TechDays, 2010
[3]: Moore, Gordon. "Progress in Digital Integrated Electronics" IEEE, IEDM Tech Digest (1975) pp.11-13.
[4]: http://www.itrs.net/Links/2010ITRS/2010Update/ToPost/2010Tables_ORTC_ITRS.xls
[5]: Brooks, Fred P.. No Silver Bullet — Essence and Accident in Software Engineering. Proceedings of the IFIP Tenth World Computing Conference. 1986: 1069–1076.