下载本文的PDF版本 PDF

语言、层级、库和寿命

新的编程语言每天都在诞生。为什么有些语言成功了,而有些却失败了?

JOHN R. MASHEY,TECHVISER

在过去的50年里,我们已经看到许多编程系统出现又(大部分)消失,尽管有些系统已经存在了很长时间,并且可能会持续存在:几十年?几个世纪?几千年?关于语言设计、抽象层级、库以及由此产生的寿命的问题有很多。为什么会出现新的语言?为什么有时编写新的软件比修改可以工作的旧软件更容易?多少个不同的语言层级是有意义的?为什么有些语言在“更好”的语言面前仍然存在?

我们可以从过去50年的编程系统中收集到对当前时代的见解。对于遥远的未来,弗诺·文奇精彩的科幻小说《深空之渊》显得非常真实。年轻的主人公范恩加入了一艘星际飞船的船员,正在学习高价值的职业“程序员考古学家”,因为船员的安全取决于找到所需的代码、使用它并在不破坏任何东西的情况下修改它的能力。他最初对发现的代码感到震惊

程序都是垃圾……编程可以追溯到时间之初……这里有些程序是五千年前编写的,那时人类甚至还没有离开地球。令人惊奇的是——令人恐惧的是……这些程序仍然有效……在最底层是一个运行计数器的程序。一秒一秒地,Qeng Ho 从人类第一次踏上旧地球月球的那一刻开始计数。但如果你更仔细地看它……起始时刻实际上大约晚了 1500 万秒,是人类最早的计算机操作系统之一的 0 秒……

“我们应该重写所有代码,”范恩说。

“已经做过了,”苏拉说。

“已经尝试过了,”布雷特纠正道……“你和一千个朋友需要工作大约一个世纪才能重现它…… 而且你猜怎么着——即使你做到了,当你完成时,你也会有自己的一套不一致之处。而且你仍然无法与现在和将来可能需要的所有应用程序保持一致……”

“这一切的词语是‘成熟的编程环境’。”1

任何老 Unix 用户都会觉得 Unix 的 1970 年 1 月 1 日日期会被如此长久地奉为神圣而感到好笑。我们已经开始了一个过程,许多人的生活已经依赖于软件的正确运行,并且很可能变得更加依赖。曾经只能在大型系统上运行的软件向下迁移到更多的小型计算机上。目前的一些手机使用 300-MHz CPU,其运行速度高于 1990 年之前任何商业生产的 CPU。有些手机拥有 64 MB 的内存,与 1980 年代后期许多昂贵的系统相媲美。文奇的书从当前的小型“智能尘埃”计算机推断,假设从现在起 5000 年后,大多数计算将由其超强大、几乎看不见的后代完成,其中包含多层软件(以及不止几个后门)。在美国,我们平均每人拥有约 100 个 CPU,这个数字传统上每十年增加十倍。随着无线传感器网络的普及,我们面临着未来大多数物体都拥有 CPU 并通过无线电连接在一起的未来。

软件已经很重要,将来会继续更加普遍地重要,而语言选择将始终是软件质量、可理解性和可用性的重要组成部分。

语言战争永无止境

语言战争似乎永无止境。关于早期语言的经典参考文献是珍·萨米特的《编程语言——历史和基础》2,其中讨论了截至 1969 年大约 120 种重要的语言,以及理查德·韦克斯布拉特的《编程语言史》3,其中记录了一次会议,该会议选择了 1967 年之前创建并在 1977 年仍在使用的 10 种重要语言。在这 10 种语言中,许多人仍然用 Basic、Cobol 和 Fortran 编写大量新代码。其他语言在其特定领域仍然流行(Lisp、APT 和偶尔的 Snobol),以及一些历史悠久的 IBM 语言(PL/I、GPSS)仍然存在。120 种语言中的大多数已经消失了。

成功的语言继续从小型的行业或大学团体、商业供应商或通过联盟产生。事实上,凭借当前的 CPU 和软件,个人更容易创建有趣的语言。到 2020 年,当这些 CPU 变得可笑地古老时,它应该变得更加容易。

几个网站广泛地编目了计算机语言,包括 http://hopl.murdoch.edu.au。

层级和杠杆

与计算机不同,人类不容易为了更高的性能而进行重新设计。程序员的能力差异很大,但每个人在阅读和编写代码方面都有实际的 I/O 限制。许多软件进步来自于使用更快的计算机,对人来说更有效率,但对计算机来说效率较低。计算机性能和存储的显着提高与代码的扩展相匹配。

在每个计算机类别(大型机、小型机、微型计算机)中,人们倾向于首先编写汇编代码以获得性能,然后随着计算机类别的性能变得更强大而使用更高级别的语言。通常,更强大的语言是后期绑定的,将更多决策移近执行时间。典型的进展如下

汇编语言通常与 CPU 指令一一对应。

宏汇编器与 CPU 指令一对多,适用于标准代码序列的参数化扩展。人类仍然负担着大量工作,包括安排数据存储、分配寄存器和选择高效的指令序列。前两个级别对于大多数程序员来说已经(并且值得庆幸地)消失了,但一些小型嵌入式微处理器和许多 DSP(数字信号处理器)仍然以这种方式编程。

更高级别的算法语言,如 Fortran 和 C,自动化了许多低级细节,因此人类可以专注于算法。面向对象,受到 Simula 和 Smalltalk 的启发,并在 C++、Java 和 C# 中广泛应用,通过更好的数据结构改进了代码并简化了维护。

领域特定语言,如 APT(自动编程工具),旨在针对目标领域,因此可以提供那里需要的特定操作,而忽略其他一切。文本处理语言,如 roff、troff、SGML、Scribe、TeX、Postscript 和 HTML,是这个组中常见的成员,其中一些本身就是强大的编程语言。

非常高级的语言,如 APL、Mathematica 和计算机电子表格,让人们可以用最少的编程进行广泛的计算。APL 于 1960 年代后期首次实现,对许多类型的问题具有强大的杠杆作用,但因其被认为是只写而不读而备受喜爱或憎恨。许多电子表格用户不认为自己是程序员,但他们所做的工作与多年前需要大量 Fortran 的工作相同。

脚本语言,如 Perl、PHP、Javascript 和 Python,在代码不需要如此高效,但人类效率、易于表达和维护是最高优先级的情况下被广泛使用。有时,计算环境的变化需要新型语言以允许广泛使用。几十年来,编程分布式应用程序一直是一项困难的任务,只能由专家处理,尽管人们反复尝试编写更好的语言或工具包来创建它们。Web 极大地改变了这一点。

作为不同级别语言演变的示例,让我们回到 1970 年代的贝尔实验室,这是帮助创建当前计算重要基础的几个环境之一。当然,它的根源甚至可以追溯到更久远。

在 1970 年, “真正的计算机”仍然是大型机,尽管小型机的使用越来越多。DEC(数字设备公司)16 位 PDP-11 于 1970 年推出,尤其重要的是,PDP-11/45 于 1972 年出现,配备高达 248 KB 的 MOS(金属氧化物半导体)内存。到 1975 年,PDP-11/70 允许大幅增加到 4 MB,尽管每个程序仍然限制为 64 KB 指令和 64 KB 数据。一些站点在 11/45 上支持 16 个同时用户,并通过英勇的努力,在 11/70 上支持 48 个用户。VAX-11/780 于 1977 年推出,并在更广泛的范围内普及了低成本的 32 位计算。到十年末,小型机成为“真正的计算机”,而 32 位微型计算机开始出现。

在 1970 年,应用程序语言(如 Fortran、Cobol 和 PL/I)被广泛使用,但许多应用程序和大多数系统代码仍然用汇编语言编写,而操作系统可以在机器之间移植的想法是可笑的。最后,Unix 被移植到许多系统,C 被广泛使用,并且应用程序正在使用各种更高级别工具的组合编写。

1973 年,PWB(程序员工作台)在贝尔实验室软件工具部门开始开发。4 它支持一个 1000 人的部门,该部门生产在各种大型机和小型机上运行的数据库和通信应用程序软件产品。它希望将许多编程活动从昂贵的大型机转移到基于 Unix 的通用开发环境中,以避免为每个目标系统创建独特的支持软件。需要说服编程部门改变他们的方式,Unix 是一件好事,小型机不是玩具,他们应该将预算转移到工具部门以购买更多的 PDP-11。

1973 年,现有的几十个 Unix 系统中的大多数是各个部门的财产,供少数人用于自己的项目,并以非正式的方式进行管理,有时安全性极低。PWB 站点是贝尔实验室中第一个运行“Unix 计算机中心”的站点,供部门(包括打字员)共享通用使用。多年来,它是最大的单一 Unix 站点,并且经常遇到早期的可扩展性、系统管理、收费、安全性、自动化以及非技术用户的可用性问题。

1973 年,Ken Thompson 的 Unix shell 主要用作交互式解释器,但具有一些基本的脚本编写能力,包括单独的 IF 和 GOTO 命令。1974 年,我使用 shell 脚本为一个潜在的客户部门构建了一个小型文档管理包,发现这是一种快速构建此类软件的好方法,但存在尴尬的限制。在 1975 年和 1976 年,PWB 的 shell 获得了简单的变量、更好的控制结构(IF-THEN-ELSE-ENDIF、SWITCH、WHILE)和中断捕获。后来成为 $HOME(主目录)和 $PATH(命令的变量搜索路径)的变量可以追溯到这项工作。

Shell 编程迅速成为 PWB 用户帮助自动化其工作的广泛机制。5 Shell 过程消耗了大量的 CPU 时间,以至于以前单独的命令(如 IF、GOTO 和 SWITCH)被移入 shell 本身,从而显着提高了性能。Steve Bourne 当时正在计算研究部门开发一种全新的 shell,经过多次讨论,他开发了一种全新的设计,其性能和功能非常有趣,最终取代了 PWB shell。这些变量被概括为为第 7 版 Unix 设计的“环境变量”。

Al Aho、Peter Weinberger 和 Brian Kernighan 编写了 awk,这是当前一些流行的脚本语言的哲学祖先。在 1970 年代,贝尔实验室正忙于构建计算机系统以改进贝尔系统运营,其中许多系统都建立在 Unix 之上,甚至在交付的软件中使用了脚本语言。CRAS(电缆维修管理系统)是一个数据挖掘软件包,它集成了来自其他几个系统的数据,分布在 IBM 大型机和 Unix 小型机之间,必须快速部署,并且在组织结构大调整时期对依赖于组织结构的需求很敏感。6 第一个版本包括 10 KLOC(千行代码)的 C 代码加上 15 KLOC 的 shell+awk 脚本,并在现场快速修改以适应新揭示的客户需求。Kernighan 的办公桌上出现了一个很长的这些脚本列表——令他非常惊讶,因为 awk 的作者从未期望在生产中如此广泛地使用它。

Shell 脚本使用后期绑定、高级解释来组合更高性能的编译组件。Awk 为我们提供了一种比 C 更灵活的语言,尽管我们有时会在需求稳定后将大量使用的 awk 转换为 C 以提高性能。我们有时希望有一个 awk 编译器。提高语言级别在那个十年中极大地提高了生产力,因为 C 取代了汇编语言,而脚本级语言极大地增强了 C。

最好重用现有代码,而不是编写新代码。启用这种重用的子例程库至少可以追溯到 1947 年 EDSAC 上的 David Wheeler。

与级别问题相关的是“大规模编程”问题。编写代码太容易了,然后未能很好地组织和记录它,以至于其他人可以找到并重用它,或者更难的是修改它。这是文奇主人公的问题,有时也是“只写”APL 的问题。多年来,已经取得了实质性进展——从简单的库到软件开发环境系统,再到今天的用于共享和搜索的基于 Web 的工具——但必须继续改进。

贝尔实验室的道格·麦克罗伊在 1969 年说的话至今仍然适用

“软件组件(例程),为了广泛适用于不同的机器和用户,应该以族的形式提供,根据精度、鲁棒性、通用性和时空性能排列……我们无疑是通过落后的手段生产软件。在与硬件人员的对抗中,我们无疑会吃亏,因为他们是工业家,而我们是佃农。” 7

接受度和寿命

许多人提出甚至实现了优秀的语言,但从未被广泛接受。为了获得广泛的支持,一种新语言需要实现以下几个目标之一。

首先,它可能有效地解决一些新的问题领域。如果它出现得早,如果人们容忍它的缺陷,如果它获得支持,并且如果缺陷不断得到修复,那么即使继任者更优雅,继任者也很难取代它。

其次,它可能会大大提高抽象级别,极大地简化某些编程任务,并在额外的性能消耗可以接受的时候出现。一些好的想法只是出现得太早了。一些其他的想法被证明在大多数硬件上都很难实现,例如 Algol 的“按名称调用”。与汇编语言相比,C 提高了级别,提供了接近高效可实现硬件的功能,并且编译器优化不断快速改进,足以抵御低级别竞争对手。

第三,它可能处理现有语言处理不佳的新数据类型。诸如向量化、并行化或并行多媒体等功能需要语言扩展,有时需要新语言,因为旧语言可能难以适应。在 C 中使用描述嵌入式处理器中正在创建的各种新功能方面正在进行有趣的实验,因为 C 的正常数据类型难以处理对于 10 位、12 位和 24 位打包数据项的混合高效的硬件。诸如 SystemC 之类的扩展用于硬件描述。C 在 1980 年代对 RISC 处理器的设计产生了重大影响,现在看来,当前的硬件创新可能会影响 C 的变体。

最后,它可能由大型联盟或强大的供应商支持,因此可能会持久存在很长时间。

任何想要创建一种在美学上比某些现有、广泛使用的语言更简洁,但不兼容,并且好 10% 的新语言的人都应该抵制诱惑。在现有领域,一种新语言需要在重要的指标上好得多才有任何机会。最好的机会发生在性能大幅提升或应用程序发生重大变化(例如 Web)时。

在任何给定的问题领域,都有空间容纳不同级别的语言堆栈,但在同一领域同一级别上没有太多空间容纳许多不同的竞争对手。有时,语言会被来自上方和下方的竞争对手的组合挤压。例如,曾经流行的位于汇编语言之上但低于 C 的语言——例如 Intel PL/M、P. J. Plauger 的 LIL、Niklaus Wirth 的 PL/360 和 IBM PL/S——被 C 挤出了市场。

一些未来的可能性

首先,当新硬件支持新的数据类型时,要么必须扩展语言,要么会出现新的语言。我们正处于嵌入式 CPU 指令集重大创新的早期阶段。在某些情况下,人们可以在数小时内发明新的指令集并进行试验。C 和 C++ 要么会大幅扩展,要么会被在该领域取代。

其次,紧耦合并行性持续增加,通过多处理器,越来越多地在单个芯片上,其中一些芯片已经拥有 100 多个 CPU。一些应用程序可以使用普通的顺序代码,但为了让其他应用程序利用这种计算能力,更好的语言会有所帮助。当然,人们已经为此努力了几十年,许多大型并行应用程序仍然用 Fortran 编写,并行编程仍然很困难。廉价的片上多处理器可能会催生成功的新语言。

第三,松耦合并行性将需要帮助,尤其是在网络规模和性质随着更多智能尘埃和移动系统而变化时,在这些系统中,节点来来往往。利用所有这些比管理紧耦合并行性更难,并且这里应该存在语言机会,就像互联网上出现的那样。

第四,更高性能的硬件总是允许更晚的绑定时间、更多的解释或更多的即时编译。许多人的理想是以最高级别、后期绑定进行编写,并让软件系统负责动态重新编译软件中大量使用的部分以使其更快,就像在某些动态二进制翻译系统中完成的那样。可能会有空间容纳为这些想法设计的新语言。

构建更好的语言

软件设计人员必须继续构建更好的语言,以利用不断提高的性能来适应不变的人类特征。他们必须不断提高抽象级别,以便人类可以忽略更多细节。组织软件的工具需要不断改进,以便人们可以更轻松地发现现有代码、重用它并对其进行修改。

在过去的 50 年里,我们已经看到语言的兴衰,有时留下了关键软件的考古遗址,这些软件的原始硬件早已无法运行,一些编写者也是如此。一些语言表现出惊人的寿命,尽管后来开发了许多“更好”的语言。实际上,任何成功的东西似乎都会建立起一个代码库,以至于它可能永远不会消失。我们需要不断找到更好的方法来表达我们的编程思想,让我们能够安全地重写旧代码。

否则,在公元 7000 年,文奇的范恩是否还会对 Unix C 定时器例程感到困惑?很有可能!

“人们所做的恶事会在他们死后留存,而好事往往会与他们的尸骨一同埋葬。”——威廉·莎士比亚,《裘力斯·凯撒》,第三幕,第二场。

参考文献

1. 文奇,V. 1999. 深空之渊。纽约:托尔,222-228。

2. 萨米特,J. 1969. 编程语言——历史和基础。恩格尔伍德崖,新泽西州:普伦蒂斯-霍尔。

3. 韦克斯布拉特,R.,编辑。1981. 编程语言史。纽约:学术出版社。(1978 年 6 月 1-3 日在加利福尼亚州洛杉矶举行的 SIGPLAN 编程语言历史会议的最终论文集。)

4. 多洛塔,T. 和 J. 马希。1976. 程序员工作台简介。第二届国际软件工程会议论文集(10 月 13-15 日),IEEE 76CH1125-4 C:164-168。

5. 马希,J. 1976. 使用命令语言作为高级编程语言。第二届国际软件工程会议论文集(10 月 13-15 日),IEEE 76CH1125-4 C:169-176。

6. 博格斯,P. 和 J. 马希。1982. 电缆维修管理系统。《贝尔系统技术期刊》61(7 月-8 月),第 2 部分:1275-1291。

7. 麦克罗伊,M.D. 1969. 大规模生产的软件组件。在《软件工程》中,编辑:P. 瑙尔和 B. 兰德尔。德国加米施:北约报告(10 月 7-11 日)。

喜欢它,讨厌它?请告诉我们

[email protected] 或 www.acmqueue.com/forums

约翰·马希,风险资本家和技术公司的顾问,在多个技术顾问委员会任职,并且是计算机历史博物馆的理事。他在贝尔实验室工作了 10 年,从事 PWB/Unix 工作,包括文本处理(troff MM 宏)、命令语言、Unix 进程记帐、安全性以及帮助 Unix 广泛访问所需的其他问题。后来,他管理了基于 Unix 的应用程序和软件开发系统的开发。他是 MIPS RISC 架构的设计者之一,SPEC(标准性能评估公司)基准测试组的创始人之一,以及 Silicon Graphics 的首席科学家。他的兴趣长期以来包括硬件和软件之间的交互。他获得了宾夕法尼亚州立大学的数学学士学位以及计算机科学硕士和博士学位。

© 2004 1542-7730/04/1200 $5.00

acmqueue

最初发表于 Queue vol. 2, no. 9
数字图书馆 中评论本文





更多相关文章

马特·戈德博尔特 - C++ 编译器中的优化
在为编译器提供更多信息方面需要权衡:它会使编译速度变慢。链接时间优化等技术可以为您提供两全其美的效果。编译器中的优化不断改进,即将到来的间接调用和虚函数分派的改进可能很快就会带来更快的多态性。


乌兰·德根巴耶夫、迈克尔·利普奥茨、汉内斯·帕耶 - 作为合资企业的垃圾回收
跨组件跟踪是一种解决跨组件边界的引用循环问题的方法。只要组件可以形成具有跨 API 边界的非平凡所有权的任意对象图,就会出现此问题。CCT 的增量版本在 V8 和 Blink 中实现,从而能够以安全的方式有效且高效地回收内存。


大卫·奇斯纳尔 - C 不是一种低级语言
在最近的 Meltdown 和 Spectre 漏洞之后,值得花一些时间研究根本原因。这两个漏洞都涉及处理器推测性地执行超出某种访问检查的指令,并允许攻击者通过侧信道观察结果。导致这些漏洞以及其他几个漏洞的功能被添加进来,是为了让 C 程序员继续相信他们正在使用低级语言进行编程,而这种情况在几十年前就不复存在了。


托比亚斯·劳因格、阿卜杜勒贝里·沙巴内、克里斯托·威尔逊 - 你不应该依赖我
大多数网站都使用 JavaScript 库,其中许多库已知是易受攻击的。了解问题的范围,以及库被包含的许多意想不到的方式,只是改进情况的第一步。这里的目标是,本文中包含的信息将有助于为社区提供更好的工具、开发实践和教育工作。





© 保留所有权利。

© . All rights reserved.