近日,Scala语言的创始人Martin Odersky接受了Artima的一系列访谈。Martin Odersky在2001年开始创立Scala语言,最初的动机是因为对Java的一些特性感到不满,想要创建一个比Java更高级的语言。他基本达到了这个目的:Scala成为了Java的首选替代之一。如果你对Scala语言还不太了解,可以参考Scala编程语言简介。
访谈共分三个系列,本文是第一个系列。在这部分节选的内容中,Martin Odersky详细的描述了他创建Scala的前因后果:他是如何创建这个基于JVM和Java类库的、不同于Java的语言的。
因编译器而着迷
Artima:让我们从头开始。您是如何开始介入编程语言的?
Martin Odersky:我最喜爱的科目一直都是编译器和编程语言。1980年,当我在读大学的时候,第一次接触编译器,我就马上想自己建立一个编译器。那时候我唯一可以买得起的电脑是Sinclair ZX 80,它只有1KB的RAM 。幸运的是,不久后我有了一个性能更强大的机器Osborne-1,它是世界上第一款"便携式"(笔记本)电脑,看上去就像一个倾斜90度的缝纫机。它有一个5英寸的显示屏,每行显示52个字符。但它有一个56KB可用的RAM以及两个90K的软盘驱动器。
在那些日子里,我花了一些时间与我大学里的另一名学生Peter Sollich一起研究。我们一起了解了一种新语言Modula-2,我们发现它非常棒,而且设计良好。因此,我们计划编写一个适用于8位Z80计算机的Modula-2编译器。但是出现了一个小问题,Osborne附带的唯一语言是Microsoft Basic,这完全不适合我们的想法,因为它甚至不支持带参数的程序,只能使用全局变量。而当时的其他编译器对于我们来说又都太昂贵了。因此,我们决定采用经典的bootstrapping(引导)技术。Peter使用Z80汇编语言为一个小小的Pascal子集编写了第一个编译器。然后,我们不断改进这个编译器,使它能够逐渐编译稍微大量的语言。经过几代版本后的改进,直到我们可以编译所有的Modula-2语言。它可以产生解释后的字节码以及Z80二进制码。该字节码是当时所有系统中最简洁的,其二进制版本是当时8位机上最快的。我们的这个编译器在当时看来是能力相当不错的系统。
我在我们即将要完成我们的编译器之前,Borland带着其Turbo Pascal横空出世,同时正在考虑入主Modula-2市场。事实上,Borland决定购买我们的Modula-2编译器,并将以Turbo Modula-2的名字出售,适用于CP/M芯片,并想要开发其IBM PC版本,我们提议为他们编写IBM PC版本,但他们告诉我们,他们对于这个版本的开发已经做好了安排。但不幸的是,这个版本的开发周期远远超出了他们的计划。3、4年后,其编码实现小组从公司中独立出来,并推出了TopSpeed Modula-2。在没有IBM PC版本时,Borland继Turbo-Modula-2之后就再也没有任何市场竞争力了。
当我们完成Modula-2编译器时,Borland提议要雇用Peter和我。于是Peter去加入了他们的行列。我曾经也想这样做,但有个问题是,我仍然还有一年的课程没有读完,而且还要计划读硕士。当时我很受诱惑,甚至想过退学。但最后,我决定坚持读完大学。之后,在做硕士项目期间(有关增量分析的课题),我发现我更喜欢做研究。于是最终我放弃了加入Borland编写编译器的想法,而是继续在苏黎世ETH攻读Niklaus Wirth的博士,Niklaus Wirth是Pascal和Modula-2的发明者。
为了更好的Java而努力
Artima:Scala是如何出现的?Scala的发展史是什么样的?
Martin Odersky:在我的苏黎世生活快要结束的时候,大概是1988到1989年,我开始非常喜欢函数式程序设计。于是,我一直留在那里做研究,最终成为一名德国卡尔斯鲁厄的大学教授。我最初的工作偏向于编程的理论方面,比如call-by-need lambda(惰性λ)演算。这项工作是同Phil Wadler共同进行的,他当时在格拉斯哥大学。有一天,Phil告诉我,他的研究组里一个很勤奋的助教听说有一种新的语言要被推出,目前这种语言仍处于alpha版本阶段,语言的名字为Java。这个助教告诉Phil:"看看这个Java,它所具有的灵活性。它拥有字节码,它可以运行在网络上,它具有垃圾收集功能。这个Java将要毁灭你们。你们准备怎么应对?" Phil说,是的,也许他说的有些道理。
对此的回应就是,Phil Wadler和我决定从函数式程序设计中提取出一些想法,并把这些想法转移到Java空间。这一努力成就了一个新语言Pizza,它具有函数式程序设计的三个特点:泛型、高阶函数以及模式匹配。Pizza最初发布于1996年,是在Java发布的一年之后。Pizza是比较成功的,因为它表明,我们可以在JVM平台上实现函数式语言的特性。
然后,我们接触了来自Sun核心开发团队的Gilad Bracha和David Stoutamire。他们说:"我们对你们一直所研究的泛型非常感兴趣,让我们一起做一个关于泛型的项目吧。"那就是GJ(泛型Java)。因此,我们于1997/98年开发了GJ,6年后,对它进行一些补充,使之成为了Java 5中的泛型功能。特别是,补充了由Gilad Bracha和奥胡斯大学的人们一起独立开发的Java泛型通配符。
虽然我们的泛型扩展被搁置了6年,但Sun公司对于我为GJ所开发的编译器表现出了浓厚的兴趣。经证明,我所写的编译器比他们的第一个Java编译器更稳定、更易于维护。因此,他们决定从2000年推出的1.3版本开始,将GJ编译器作为其标准的Javac编译器。
然后,为了比Java更好的语言
Martin Odersky:现在,经过Pizza和GJ的经历,我有时会感到沮丧,因为Java是一个具有非常强的约束的语言。因此,很多事情都不能像我想象的那种方式那样去做–那种我原本确信是正确的方式。所以本来,本质上我的工作是集中于让Java变得更好,但在那之后,我决定,现在是时候应该后退一步看看了。我想要从零开始,看看我能否可以设计出一些比Java更好的东西。但与此同时,我知道我不能从零开始。我需要借助一个现有的基础架构,否则这只是不切实际地引导自己去无中生有,没有任何类库、工具等等。
所以我决定,即使我想要设计出一种不同于Java的语言,始终还是要借助Java的基础架构–JVM和它的类库。这就是我的想法。我认为在那个时候,这是一个很好的机会,那时候我正在洛桑联邦理工大学担任教授,这为我提供了一个极好的独立研究的环境。我可以组建一个小型研究组。
开始的时候,我们非常激进。我们想要在一个现有的非常好的模型上创建一些东西,该模型为join calculus(连接演算)。我们创建了一个连接演算的面向对象版本Functional Nets,以及一种新语言Funnel。但是,又过了一段时间,我们发现,Funnel是一个非常纯粹的语言,并不一定很实用。Funnel是建立在一个非常小的内核之上。很多人们通常认为理所当然的事情(如类,或模式匹配)都只能通过编码到内核才能实现。从学术的角度来看这是一项非常优雅的技术。但运用于实际它就并不那么好。初学者觉得这种必要的编码相当困难,而高手们却觉得不得不一次又一次地编码非常无聊。
因此,我们决定再次从头开始,并做一些介于Funnel(非常纯粹的学术语言)和GJ(非常实用但却存在一些限制的语言)中间的技术。我们希望创造一些能够实用和有价值,同时又比Java高级的东西。在大约2002年时,我们开始着手进行这种语言,称之为Scala。首次公开发布是在2003年。相对比较大规模的一次重新设计是在2006年初。从此,它开始稳步成长。
更好的Java受到的约束
Artima:您说您那时候感到很沮丧,遇到一些约束,需要向后兼容Java。您能否提供一些遇到约束的具体的例子?
Martin Odersky:在泛型设计中,有很多非常强硬的约束。其中最强、最难以应付的是,它必须充分地向后兼容非泛型Java。Collections类库只停留在1.2版本,而且仅仅因为泛型的出现,Sun不准备推出全新的Collections类库。因此,只能完全透明工作。(51CTO编者:有关Collections类库的更多内容,可参考这篇基于JDK 5.0一些collection类的使用总结,以及《Java语言的科学与艺术》一书中的Collection层次结构章节。)
这就是为什么总会存在一些相当难看的东西。你总是不得不使用具有泛型类型的非泛型类型,即所谓的raw(原始)类型。还有,你不能改变数列行为,否则就会有未经检查的警告。最重要的是,你不能利用数组做你想做的很多事情,比如生成一个具有类型参数的数组。后来在Scala,我们知道了实际上能如何实现这些事情,但是这可能仅仅是因为我们给Scala设置的条件是协变数组。
Artima:您能否就Java的协变数组详细说明一下该问题?
Martin Odersky:当Java刚出现时,Bill Joy和James Gosling以及其他Java组成员都认为,Java应该有泛型,只是他们没有足够的时间做出详细设计。所以由于Java中没有泛型,至少最初阶段没有,他们就认为,数组不得不是协变的。例如,这意味着一个字符串(String)数组是一个对象(Object)数组的子类型。其原因是他们希望能够重写,比如,一个"通用"排序方法,采用了一个对象数组和一个用来排序该数组的比较器,然后让你传送一个字符串数组的参数给它。通常情况下这属于类型不健全。这就是为什么在Java中你会获得一个数组存储例外。这实际上也证明,这种同样的事情引起了对于数组泛型实现的需求。这就是为什么在Java中泛型并不好使。你不能定义一个字符串的列表数组,这是不可能的。你只能被迫使用难看的原始类型,永远都只能是一个列表数组。因此,这有点类似原罪。他们对此做出了非常迅速的回应,认为这是一个快速破解。但随后实际上每一个设计决定都被毁灭了。因此,为了不陷入同样的陷阱,我们不得不中断,并提出现在我们将不向上兼容Java,我们也想做一些不同的事情。
编者后记
Scala到目前为止还是一个相对小众的语言,在TIOBE每月的排行榜上都在20到30之间浮动,与每月排名第一的Java在流行程度上仍有很大的差距。然而Scala在数年之间已经得到了越来越多开发者的关注,在国外的开发者讨论区中常常会看到有Scala的专区。Scala在现在以及未来的开发界绝对是一个不可忽视的语言。