English Version

关于语言设计的五个问题

2001年5月

(这些是我在2001年5月10日MIT编程语言设计小组讨论会上所做的笔记。)

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

编程语言是人们与计算机交流的方式。计算机对于任何无歧义的语言都会同样满意。我们有高级语言的原因是因为人们无法处理机器语言。编程语言的要点是防止我们可怜脆弱的人类大脑被大量细节所淹没。

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

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

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

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

2. 为自己和你的朋友设计。

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

当语言为其他人设计时,总是特定的一群其他人:没有语言设计师聪明的人。所以你得到一种居高临下的语言。Cobol是最极端的例子,但很多语言都充斥着这种精神。

这与语言的抽象程度无关。C是相当低级的,但它是为其作者使用而设计的,这就是为什么黑客喜欢它。

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

我对这个问题很感兴趣,你如何设计一种最好的黑客会喜欢的语言?我碰巧认为这与如何设计一种好的编程语言是同一个问题,但即使不是,它至少是一个有趣的问题。

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

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

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

4. 追求简洁。

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

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

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

5. 承认黑客的本质。

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

黑客喜欢做的是编写伟大的程序。而且我认为,至少在我们自己的心中,我们必须记住,编写伟大的程序是一件令人钦佩的事情,即使这项工作不容易转化为研究论文的传统智力货币。在智力上,设计程序员会喜欢的语言与设计一个包含你可以发表论文的某些想法的糟糕语言同样有价值。

开放性问题

1. 如何组织大型库?

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

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

这是一个开放性问题,在这个意义上我多年来一直在思考它,但仍然不知道答案。前缀语法对我来说似乎完全自然,可能除了数学。但Lisp不受欢迎可能只是因为它有陌生的语法。如果这是真的,是否要对此做些什么是另一个问题。

3. 基于服务器的软件需要什么?

我认为未来二十年内编写的最令人兴奋的新应用程序中,很多将是基于Web的应用程序,意味着程序位于服务器上并通过Web浏览器与你交谈。而编写这类程序我们可能需要一些新东西。

我们需要的一件事是支持基于服务器的应用程序发布的新方式。不像桌面软件那样每年有一两个大的发布版本,基于服务器的应用程序作为一系列小变化发布。你一天可能有五到十个发布版本。而且作为规则,每个人都会总是使用最新版本。

你知道你可以设计程序以便调试吗?嗯,基于服务器的软件同样必须设计成可改变的。你必须能够轻松地改变它,或者至少知道什么是小的改变,什么是重大的改变。

另一个可能对基于服务器的软件有用的东西,令人惊讶的是,是continuations。在基于Web的软件中,你可以使用类似continuation-passing style的东西来在Web会话本质上无状态的世界中获得子程序的效果。如果不太昂贵,拥有实际的continuations可能是值得的。

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和微软似乎正在陷入某种字节码之战。但他们这样做是因为字节码是插入到过程中的方便位置,而不是因为字节码本身是个好主意。最终整个战场可能被绕过。那会很有趣。

争议性观点

1. 客户端。

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

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

2. 面向对象编程。

我意识到这是有争议的,但我不认为面向对象编程是那么了不起。我认为对于需要特定数据结构类型的某些应用程序,如窗口系统、模拟和cad程序,它是一个很好的模型。但我不明白为什么它应该是所有编程的模式。

我认为大公司的人们喜欢面向对象编程的部分原因是它产生了很多看起来像工作的东西。某些可能自然地表示为,比如说,整数列表的东西,现在可以表示为具有各种脚手架和喧嚣的类。

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

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

3. 委员会设计。

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

设计好语言需要冒险吗?许多人可能怀疑语言设计是你应该相当接近传统智慧的事情。我打赌这不是真的。在人们做的所有其他事情中,回报与风险成正比。为什么语言设计应该不同?

日语翻译