[Code翻译]程序设计语言的演变

245 阅读7分钟

本文由 简悦SimpRead 转码,原文地址 [elizarov.medium.com] (elizarov.medium.com/programming…)

编程语言不断发展。但是,是什么推动了这种演变?让我们看看一些例子,......

image.png

图片由Anne Nygård on Unsplash

编程语言的历史是成熟的演变。现有的语言不断发展,新的语言被创造出来以满足新的需求。有时会有激进的、革命性的突破,有完全的范式转变,但往往只是逐步的改进和完善。后者是本故事的主题。在任何特定的时代,编程的实践通常会领先于编程语言所提供的能力,而编程语言的设计者则认识到这一点,并迎头赶上以满足需求。让我们看一些例子来说明问题。

从GOTO到结构化代码

在早期的语言中,你不得不写很多重复的代码来完成一个简单的循环。循环是一种常见的编程模式,甚至在结构化编程之前的时代,它也被原始的高级语言所采用。所以,曾经有一段时间,你的编程语言中仍然有GOTO,但相当一部分代码有结构化循环。

10 LET N=10
20 FOR I=1 TO N
30 PRINT "Hello, World!"
40 NEXT I

我们知道,后来的一代语言不仅增加了结构化的IF语句,而且在源代码中明确了结构,最后完全废除了GOTO。这种演变在其他领域也可以看到。

对象和指针

让我们简单看一下OOP。面向对象的编程风格并不需要一种面向对象的语言。即使现在你可以找到用C语言编写的软件,其中的方法只是一种编写函数的_惯例,其第一个参数是一个指向接收器的指针。

void Point_move(Point* self, int dx, int dy) { ... }

在纯C语言中也经常实现虚拟方法,明确地保留一个虚拟方法表,在对象结构的某个地方引用方法。

然而,当年面向对象编程的兴起,巩固了语言的发展,将这些模式与我们今天所知的类和方法原生地结合起来。

随着硬件变得越来越快,在大规模的软件系统中,通过引用来处理对象变得如此流行,甚至不得不明确地使用Point*或其他一些语法符号来指定对对象的引用,这被认为是一个_锅炉板_--在处理业务对象时,你必须总是写一个语法咒语。所以它被废除了,为现代方法铺平了道路,即对所有对象实例的隐式引用,顶级应用编程语言(Python、JS、Java)都使用这种方法。

这也是一个很好的例子,说明今天无处不在的语言特性可能有非常长的历史,但在适当的时候才被主流语言普遍采用。

软件和扩展的规模

第一代面向对象的语言创建于20世纪,远早于我们今天看到的大规模软件项目(就代码行数和使用的第三方库而言)。这些语言很快就被采用了,其规模是它们的创造者所难以想象的。

最初的想法是,你可以简单地将一个类上需要的所有方法和它的声明一起声明,这种想法很快就崩溃了,导致一个典型的项目中出现了数百个 "StringUtil"、"FileUtil "和其他 "实用类",它们只是 "扩展方法 "的集合。它们基本上是以老式的前OOP风格编写的,其惯例是将调用的接收器作为第一个参数,正如我们在C语言的例子中看到的那样。因此,在21世纪为大规模开发而设计的一代语言,通常通过某种形式的一级扩展概念来整合这种模式,这并不奇怪。

模式、模板、特性

我还可以继续举更多的例子,比如被各种自动内存管理方案取代的脆弱的 "malloc"/"free "舞蹈,不方便的基于回调的编程产生了语言对循环程序的支持,重复的集合处理操作的模板导致了对标准高阶函数的支持,比如 "过滤器"、"地图 "等等。

我希望你在这里已经看到了一个共同的主题。随着编程的发展,出现了各种无处不在的代码模式。这些模式很无聊,容易出错,而且完全没有工作的乐趣。最终,它们被编程语言的设计者所认识,并作为新的功能被纳入语言,增加了整体的抽象水平,提高了开发者的生产力和工作满意度。这个故事在每一代语言中都会重复,因为更新的模式建立在一代人之前只是编程模式的基础上。

成为现代人,保持现代性

对于一种编程语言来说,现代化和保持现代化是什么意思?它意味着接受变化,接受这个不可避免的进化周期,并与之一起进化。当软件开发人员持续编写或不得不自动生成一些重复模式的代码时,它发出了一个强烈的信号:有些东西是不对的,有些语言特性是缺失的。

再来看一个例子。随着OOP设计风格的扩展,将数据的内部存储与外部可见的表示方式解耦成为规范,从而产生了getXxx(getter)和setXxx(setter)方法的惯例来实现这种封装。这种情况在企业代码库中已经持续了20多年,有大量的工具帮助生成这种模板。所以现在,只要看看一种语言是否有或缺乏对这种属性模式的内置支持,我们就可以知道一种语言是否跟得上现代大规模软件开发的需要。

移除过时的功能

让我们回到我们开始的例子--从用GOTO编程到现代结构化编程的过渡。真正的突破不仅来自于在语言中加入结构化的循环和条件,而且来自于对GOTO语句的完全删除。

一个典型的例子是关于空指针的臭名昭著的 "十亿美元问题"。增加语言对更好地处理空值的支持,只是帮助开发人员编写避免空值的模板的一半解决方案。真正的突破是完全禁止将空值存储到任意的引用类型中。

这种对过时功能的清除往往是阻碍语言适应不断变化的世界的最难的障碍,导致它们在所增加的功能的重压下最终垮台。当然,这也取决于语言的惯性,其生态系统的规模。语言越广泛,它就越能承受更多的重量而不至于崩溃。但最终,查尔斯-达尔文所说的进化的一般规律也适用于编程语言。

不是最聪明的物种能够生存,不是最强壮的物种能够生存,而是能够最好地适应和调整它所处的变化环境的物种能够生存。

进一步阅读

如果你对塑造现代编程语言设计的趋势感兴趣,那么请查看我的其他相关故事。


www.deepl.com 翻译