Featured image of post 编程语言设计的五个问题

编程语言设计的五个问题

探讨编程语言设计中的关键问题,包括语言设计原则、库设计、语法选择等核心议题。

📚 返回 Paul Graham 文章目录

编程语言设计的五个问题

2001年5月

(这些是我为2001年5月10日在MIT举行的编程语言设计小组讨论准备的一些笔记。)

1. 编程语言是为人类设计的

编程语言是人类与计算机交流的方式。计算机使用任何无歧义的语言都会同样开心。我们之所以需要高级语言,是因为人类无法直接处理机器语言。编程语言的目的就是防止我们脆弱的人类大脑被大量细节所淹没。

建筑师知道某些设计问题比其他问题更个人化。最干净、最抽象的设计问题之一是设计桥梁。在那里,你的工作主要是用最少的材料跨越给定的距离。另一个极端是设计椅子。椅子设计师必须花时间思考人类的臀部。

软件也是如此。设计网络数据路由算法是一个很好的抽象问题,就像设计桥梁。而设计编程语言则像设计椅子:它完全关乎处理人类的弱点。

我们大多数人都讨厌承认这一点。设计具有伟大数学优雅性的系统听起来比迁就人类的弱点更有吸引力。数学优雅确实有其作用:某些类型的优雅使程序更容易理解。但优雅本身并不是目的。

当我说语言必须设计得适合人类的弱点时,我并不是说语言必须为糟糕的程序员设计。事实上,我认为你应该为最好的程序员设计,但即使是最好的程序员也有局限性。我想没有人会喜欢用所有变量都是带整数下标的字母x的语言编程。

2. 为自己和朋友设计

如果你看看编程语言的历史,很多最好的语言都是为作者自己使用而设计的,而很多最糟糕的语言都是为其他人设计的。

当语言为其他人设计时,总是针对特定的人群:不如语言设计者聪明的人。所以你得到的是一个居高临下的语言。Cobol是最极端的例子,但很多语言都弥漫着这种精神。

这与语言的抽象程度无关。C相当底层,但它是为作者自己设计的,这就是为什么黑客喜欢它。

为糟糕的程序员设计语言的论点是糟糕的程序员比好的程序员多。这可能是事实。但那些少数优秀的程序员编写了不成比例的大量软件。

我感兴趣的问题是,如何设计一门最优秀的黑客会喜欢的语言?我认为这个问题等同于如何设计一门好的编程语言?但即使不是,这至少是一个有趣的问题。

3. 给程序员尽可能多的控制权

许多语言(特别是为其他人设计的语言)采取保姆式的态度:它们试图阻止你做一些它们认为对你不好的事情。我喜欢相反的方法:给程序员尽可能多的控制权。

当我第一次学习Lisp时,我最喜欢它的一点是它把我当作平等的伙伴。在我之前学过的其他语言中,有语言本身,还有用语言写的程序,两者是分开的。但在Lisp中,我写的函数和宏与构成语言本身的那些完全一样。如果我想的话,我可以重写语言。它具有与开源软件相同的吸引力。

4. 追求简洁

简洁被低估甚至被轻视。但如果你深入黑客的内心,你会发现他们真的很喜欢它。你多少次听到黑客深情地谈论在APL中如何只用几行代码就能做令人惊叹的事情?我认为任何真正聪明的人真正喜欢的东西都值得关注。

我认为几乎任何能让程序更短的事情都是好的。应该有大量的库函数;任何可以隐含的东西都应该隐含;语法应该简洁到极致;甚至事物的名称也应该简短。

而且不仅仅是程序应该简短。手册也应该薄。手册的很大一部分被用于澄清、限制、警告和特殊情况。如果你强迫自己缩短手册,最好的情况是你通过修复语言中需要如此多解释的东西来实现。

5. 承认编程的本质

很多人希望编程是数学,或者至少是类似自然科学的东西。我认为编程更像建筑。建筑与物理学有关,因为建筑师必须设计不会倒塌的建筑物,但建筑师的真正目标是建造伟大的建筑,而不是发现静力学的新知识。

黑客喜欢做的是创造伟大的程序。我认为,至少在我们自己的心中,我们必须记住,编写伟大的程序是一件值得钦佩的事情,即使这项工作不能轻易转化为研究论文这种传统的知识货币。从智力上讲,设计一门程序员会喜欢的语言与设计一门糟糕的、但能体现某个可以发表论文的想法,同样有价值。

1. 如何组织大型库?

库正在成为编程语言越来越重要的组成部分。它们也在变得更大,这可能很危险。如果找到能完成你想要的库函数比你自己写代码花的时间还长,那么所有这些代码除了让你的手册变厚外什么也没做。(Symbolics手册就是一个例子。)所以我认为我们必须研究组织库的方法。理想情况是设计它们,使程序员能够猜到什么库调用会做正确的事情。

2. 人们真的害怕前缀语法吗?

这是一个开放问题,因为我已经思考了多年但仍然不知道答案。前缀语法对我来说似乎很自然,除了数学可能例外。但可能是Lisp的不流行仅仅是因为有不熟悉的语法。如果这是真的,是否要对此做些什么是另一个问题。

3. 服务器端软件需要什么?

我认为未来二十年编写的许多最令人兴奋的新应用程序将是基于Web的应用程序,即坐在服务器上通过Web浏览器与你对话的程序。编写这类程序我们可能需要一些新的东西。

我们需要的一件事是支持服务器端应用程序的新发布方式。与桌面软件每年有一两次大发布不同,服务器端应用程序作为一系列小更改发布。你可能每天有五到十次发布。而且通常每个人都会使用最新版本。

你知道如何设计程序使其可调试吗?同样,服务器端软件必须设计得可更改。你必须能够轻松地改变它,或者至少知道什么是小改变什么是重大改变。

对服务器端软件可能有用的另一件事,令人惊讶的是,是续体。在基于Web的软件中,你可以使用类似续体传递风格的东西来在Web会话这个本质上无状态的世界中获得子程序的效果。也许如果代价不是太高的话,拥有真正的续体会很有价值。

4. 还有什么新的抽象需要发现?

我不确定这个希望是否合理,但我个人真正想做的一件事是发现一个新的抽象 — 一个能带来与拥有一等函数、递归或关键字参数同样大影响的东西。这可能是一个不可能的梦想。这些东西并不经常被发现。但我一直在寻找。

1. 你可以使用任何你想要的语言

编写应用程序过去意味着编写桌面软件。在桌面软件中,有很大的偏见倾向于用与操作系统相同的语言编写应用程序。所以十年前,编写软件基本上意味着用C编写软件。最终形成了一种传统:应用程序不能用不寻常的语言编写。这个传统有如此长的时间发展,以至于非技术人员如经理和风险投资家也学会了它。

服务器端软件完全打破了这种模式。使用服务器端软件,你可以使用任何你想要的语言。几乎没有人理解这一点(特别是经理和风险投资家)。一些黑客理解它,这就是为什么我们甚至听说新的、独立语言如Perl和Python。我们听说Perl和Python不是因为人们在用它们编写Windows应用程序。

这对我们这些对设计编程语言感兴趣的人来说意味着,现在可能有一个真正的受众。

2. 速度来自分析器

语言设计者,或者至少是语言实现者,喜欢编写生成快速代码的编译器。但我不认为这是使语言对用户来说快速的原因。Knuth很久以前就指出,速度只在某些关键瓶颈处才重要。任何尝试过的人都知道,你无法猜测这些瓶颈在哪里。分析器是答案。

语言设计者在解决错误的问题。用户不需要基准测试来运行得快。他们需要的是能向他们展示他们自己的程序哪些部分需要重写的语言。这就是实践中速度的来源。所以也许如果语言实现者把原本用于编译器优化的一半时间用来写一个好的分析器,会是一个净收益。

3. 你需要一个应用程序来驱动语言的设计

这可能不是一个绝对的规则,但似乎最好的语言都是与它们被用来编写的某些应用程序一起演变的。C是由需要它进行系统编程的人编写的。Lisp部分是为了做符号微分而开发的,McCarthy如此渴望开始,以至于在1960年第一篇关于Lisp的论文中就在写微分程序。

如果你的应用程序解决了一些新问题,那就特别好。这往往会推动你的语言拥有程序员需要的新特性。我个人对编写一门适合编写服务器端应用程序的语言感兴趣。

[在小组讨论中,Guy Steele也提出了这个观点,并补充说应用程序不应该包括编写你的语言的编译器,除非你的语言恰好是为了编写编译器而设计的。]

4. 一门语言必须适合编写一次性程序

你知道什么是一次性程序:你为某个有限任务快速编写的东西。我认为如果你环顾四周,你会发现很多大型、严肃的程序最初都是一次性程序。如果大多数程序最初都是一次性程序,我不会感到惊讶。所以如果你想制作一门适合一般软件编写的语言,它必须适合编写一次性程序,因为这是大多数软件的幼虫阶段。

5. 语法与语义相关

传统上认为语法和语义是完全分开的。这听起来可能令人震惊,但它们可能不是。我认为你在语言中想要的东西可能与如何表达它有关。

我最近和Robert Morris谈话,他指出运算符重载在中缀语法的语言中是一个更大的优势。在具有前缀语法的语言中,你定义的任何函数实际上都是一个运算符。如果你想为你发明的新类型数字定义一个加法,你可以直接定义一个新函数来加它们。如果你在中缀语法的语言中这样做,使用重载运算符和函数调用在外观上有很大区别。

1. 新的编程语言

在1970年代,设计新的编程语言很流行。最近不太流行了。但我认为服务器端软件会使新语言再次流行。使用服务器端软件,你可以使用任何你想要的语言,所以如果有人确实设计了一门看起来比其他可用语言更好的语言,会有人冒险使用它。

2. 分时

Richard Kelsey在上一次小组讨论中提出这是一个时机已到的想法,我完全同意他的观点。我的猜测(也是微软的猜测,似乎)是很多计算将从桌面转移到远程服务器。换句话说,分时又回来了。我认为这需要在语言层面得到支持。例如,我知道Richard和Jonathan Rees在Scheme 48中做了很多实现进程调度的工作。

3. 效率

最近开始似乎计算机终于足够快了。我们越来越多地听到字节码,这至少对我来说意味着我们觉得我们有周期可以浪费。但我不认为使用服务器端软件时我们会这样。有人必须为运行软件的服务器付费,每台机器能支持的用户数将是其资本成本的除数。

所以我认为效率会很重要,至少在计算瓶颈处。快速进行I/O将特别重要,因为服务器端应用程序做很多I/O。

最终可能证明字节码不是一个优势。Sun和Microsoft似乎正在字节码领域展开某种战斗。但他们这样做是因为字节码是插入到进程中的方便位置,而不是因为字节码本身是个好主意。可能这个整个战场会被绕过。那会很有趣。

1. 客户端

这只是一个猜测,但我的猜测是大多数应用程序的获胜模型将是纯服务器端的。设计假设每个人都会有你的客户端的软件就像设计一个假设每个人都会诚实的社会的软件。这当然会很方便,但你必须假设它永远不会发生。

我认为会有大量具有某种Web访问能力的设备,你只能假设它们能支持简单的html和表单。你的手机上会有浏览器吗?你的掌上电脑会有电话吗?你的黑莓会有更大的屏幕吗?你能在游戏机上浏览Web吗?你的手表?我不知道。如果我赌注于一切都只在服务器上,我就不需要知道。把所有大脑放在服务器上要稳健得多。

2. 面向对象编程

我知道这是一个有争议的话题,但我不认为面向对象编程是那么重要。我认为它是某些需要特定数据结构的应用程序的好模型,如窗口系统、模拟和CAD程序。但我不明白为什么它应该是所有编程的模型。

我认为大公司喜欢面向对象编程的部分原因是它产生了大量看起来像工作的东西。一些自然表示为整数列表的东西现在可以表示为一个带有各种脚手架和忙碌的类。

面向对象编程的另一个吸引力是方法给你一些一等函数的效果。但这对Lisp程序员来说已经是旧闻了。当你有一等函数时,你可以根据手头任务的需要以任何适当的方式使用它们,而不是强迫一切进入类和方法的模式。

这对语言设计意味着什么,我认为,是你不应该把面向对象编程构建得太深。也许答案是提供更通用的、底层的东西,让人们设计他们想要的任何对象系统作为库。

3. 委员会设计

让委员会设计你的语言是一个大陷阱,不仅仅是因为众所周知的原因。每个人都知道委员会倾向于产生笨拙、不一致的设计。但我认为更大的危险是他们不会冒险。当一个人负责时,他可以冒险,而委员会永远不会同意。

设计一门好语言是否必须冒险?许多人可能怀疑语言设计是应该相当严格地遵循传统智慧的事情。我打赌这不是真的。在人们做的其他任何事情中,回报都与风险成正比。为什么语言设计应该不同?

英文版:paulgraham.com/langdes.html|中文版:HiJiangChuan.com/paulgraham/009-five-questions-about-language-design

📚 返回 Paul Graham 文章目录

更新记录: