Loading...

关于语言设计的五个问题

Original

2001年5月

(这些是我为2001年5月10日在麻省理工学院关于编程语言设计的讨论小组所做的一些笔记。)

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. 效率。

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

因此,我认为效率将很重要,至少在计算瓶颈中。快速进行输入/输出将尤其重要,因为服务器端应用程序进行大量的输入/输出。

最终,字节码可能并不是一个胜利。Sun和微软似乎目前正在进行一种字节码的对抗。但他们这样做是因为字节码是一个方便的插入过程的地方,而不是因为字节码本身是个好主意。最终,这整个战场可能会被绕过。这将是相当有趣的。

1. 客户端。

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

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

2. 面向对象编程。

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

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

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

我认为这对语言设计的意义在于,你不应该将面向对象编程构建得太深入。也许答案是提供更一般的基础内容,让人们设计他们想要的任何对象系统作为库。

3. 委员会设计。

让你的语言由委员会设计是一个大陷阱,不仅仅是因为大家都知道的原因。大家都知道委员会往往会产生不一致的设计。但我认为更大的危险在于他们不会冒险。当一个人负责时,他可以冒险,而委员会则永远不会达成一致。

然而,设计一种好的语言是否必须冒险呢?许多人可能会怀疑,语言设计是一个应该相对接近传统智慧的领域。我打赌这并不是真的。在其他人所做的一切中,奖励与风险成正比。为什么语言设计会有所不同?