Scala中文之前已经陆续发出了两篇Scala之父Martin Odersky的访谈。在Artima方面,访谈仍在继续,内容则逐渐向Scala语言的特性方面发展。如果您是Java程序员,或者C/C++程序员,对Scala这样与Java极其类似但又有所改进的语言感兴趣,那么推荐您阅读以下文章:
Scala创始人:创造比Java更好的语言:“你总是不得不使用具有泛型类型的非泛型类型,即所谓的raw(原始)类型。还有,你不能改变数列行为,否则就会有未经检查的警告。最重要的是,你不能利用数组做你想做的很多事情,比如生成一个具有类型参数的数组。后来在Scala,我们知道了实际上能如何实现这些事情……”
Java程序员,你为什么要关注Scala:“使用Scala我们最后所做的事是直接确定类的参数。你只需要在类名后写一个参数列表,这些就成为类的参数。不存在独立可变域和构造函数的概念,这些实际上转变成了一些我们必须要解决的问题。”
下面继续开始Martin Odersky的访谈之旅。今天,Martin Odersky将继续讲解Scala的特性,包括Scala的可扩展,以及类型的重要性。
Scala的可扩展性
Frank Sommers: 去年您在JavaOne大会的报告中,说Scala是一个“可扩展的语言”,可以随意使用。这对于一个使用这种语言的程序员来说有什么帮助呢?
Martin Odersky: 它给你带来的帮助就是不再需要混用多种专门的语言。不论项目大小、应用领域是普通的还是特殊的,你都可以使用相同的语言。这意味着,你不必担心如何从一个语言环境到另一个语言环境调用数据。
目前如果你想跨越环境调用数据,通常需要返回到低层次的描述。举例来说,如你想要在Java中执行一个SQL查询,并使用JDBC连接数据库,查询结果最终是一个字符串。这��味着程序中的一个小错字将会导致运行时错误,很可能会体现在客户端的网站上。没有编译器或类型系统能告诉你不应该出现那样的错误。这是非常脆弱和危险的。因此,如果使用一种语言,就会避免类似问题。
另一个问题是工具。如果你使用的是一个单一的语言,你可以拥有一个单一的环境,带有一些工具。但是,如果你使用许多不同的语言,你必须混合并匹配多种环境,你的工程构建会变得更加复杂和困难。
Frank Sommers: 您在上次的报告中还提到了可扩展性的概念,即Scala可以很容易扩展。你能否解释一下如何扩展?其次,对程序员有怎样的帮助?
Martin Odersky: 第一层面的可扩展性是从小到大,但我认为另外一个可扩展性的概念是指你的需求从一般扩展到特殊。你希望能够把语言扩展到你所特别在意的领域。
比如数字(numeric)类型。现有许多特殊的数字类型,例如,针对破译密码人员的big整型,针对商务人士的big小数类型,针对科学家的复数类型,这样的例子不胜枚举。每一个领域的人都深切关注数据类型,但包含所有类型的语言将会是难以驾驭的。
答案当然是说,好吧,让我们做一个包含这些类型的类库。但是,如果你真的关心这个应用程序的领域,你希望代码在访问这些类时能够像访问内置类型那样整洁圆润。于是你想要这样的扩展机制,可以让你编写这样的类库,使得类库的使用者甚至感觉不到它是个类库。对于一个类库的使用者,假设一个big小数类库, 使用BigDecimal类型应该像使用内置Int类型那样方便。
小型程序中的类型
Frank Sommers: 您刚才提到了在一种语言(而非多种语言)背景下类型的重要性。我想大多数人在编写大型程序时都会赞赏类型��有用性。当你在编写大规模程序时,类型可以帮助你组织程序,可以让程序修改具有可靠性。但是,如果我们编写小型程序,类型会起到什么帮助,例如只编写一个脚本程序?类型还同样那么重要吗?
Martin Odersky: 可能在编写小型程序时,类型的重要性会降低。类型有时候让人觉得有很多细小的地方很繁琐。通常让人厌烦的部分是类型的定义,这很多余,需要手工键入很多字符。当然,有用的部分是,类型可以帮你提示错误,可以给你提供有用的程序文档,可以为安全重构提供一张安全网。
Scala拥有类型推理功能,试图让你尽量减少键入烦人的字符。这意味着如果你编写一个脚本,你可以不写任何类型。因为你可以不必考虑,系统会为你推断。与此同时,类型就已经存在了,如果你的脚本中有类型错误,编译器会捕获错误并返回给你一个错误信息。我相信,无论是脚本还是一个大型系统,通过编译器迅速解决这个问题总是比以后再处理要方便。
你仍然需要单元测试来测试程序逻辑,但相对于动态类型语言,你不再需要大量琐碎的单元测试,如以往的类型测试。根据很多人的经验,单元测试数量远远小于动态语言。项目开发周期数会随之减少,这是我们的一些实例经验。
其他一些反对静态类型系统的人认为,它对你想表达的事情有太多限制。人们说,“我想自由地表达自己,我不想要静态类型系统来妨碍我。”根据我使用Scala的经验,我认为这是不正确的,原因有两个。首先,Scala的类型系统实际上是非常灵活的,所以它通常可以让你以一个非常灵活的方式编写代码,但是像Java的类型系统就不太灵活,使用起来就比较困难。其次是带有模式匹配,你可以以一个非常灵活的方式恢复类型信息。
模式匹配的思想是,在Scala中我可以获得一个对此一无所知的对象,然后通过一次构造,例如一个switch语句,为其针对一些模式进行匹配。如果它属于其中一个模式,还可以立即取出值域融入到本地变量。模式匹配是一个内置入Scala的构造方法。很多Scala程序都使用它。这是Scala处理事情的一个常规方式。有趣的是,通过做模式匹配你还可以自动恢复类型。你提交一个对象,对此对象你一无所知。如果有一个模式匹配成功,实际上,你就知道你拥有适合某个类型模式的代码。系统可以使用它。
由于模式匹配,你可以很容易拥有一个类型普通的系统,甚至最普通的情况类似于每个变量都是Object类型,但你仍然可以通过使用模式匹配得到所有想要得到的类型。所以在这个意义上,你可以使用Scala更好地编程,就仿佛是使用一个动态类型语言一样。您可以到处都使用Object类型,然后随处进行模式匹配。现在,人们通常不这样做,因为想要更多地利用静态类型的优点。相比之下,Java中的Analog,你不得不使用大量的类型测试(instanceof)。我完全理解人们为什么反对在所有地方都这样做。
Duck Typing(鸭子类型)
Bill Venners: 我观察到的Scala的其中一件事是,与Java类型系统相比,在Scala的类型系统中,我可以表达更多的关于程序的事情。觉得Java是一个动态语言的人往往解释说,他们对类型系统感到很沮丧,并发现如果他们摆脱静态类型,就会有更好的体验。然而似乎Scala答案是,试图让类型系统更好,改善它,让它更有用,使用起来更方便。那么,什么事情是在Scala类型系统中可以做到,而在Java类型系统中却做不到的?
Duck Typing 是一种动态类型的概念,对象的类型由其运行时���持的属性和方法决定。
Martin Odersky: 反对Java类型系统的理由之一是,它不含有duck typing。duck typing的解释为,如果一只动物,走起来像鸭子,叫起来像鸭子,就可以把它当作鸭子。翻译过来就是,如果它含有我想要的功能,那么我可以把它当作真的来对待。举例来说,我想要一个可关闭的资源。我想说,“需要有一个close方法。”我不关心它是一个File或Channel或其他任何对象。
在Java中,为了完成这个工作,你需要一个包含方法的公共接口,每个人都必须实现该接口。首先,这导致了大量的接口和许多样板代码。其次,如果在既成事实之后再考虑这个接口是不可能的。如果你先写了这个类,那么这个类就是已经存在的,你就不可以在不破坏源代码的情况下再添加新接口,除非你控制所有客户端。因此,你就受到了类型强加给你的这些限制。
Scala比Java更富表现力的一个方面是,它可以让你表达上述事情。在Scala中,可以有这样一个类型说明:带有close方法的任何对象,close方法不含参数并返回Unit(相当于Java的void)。你还可以结合其他方面的限制。你可以说:继承于某一特定类的任何类,具有某些带有签名的特殊方法。或者你可以说:继承于这个类的任何类,并含有一个特定类型的内部类。从本质上讲,你可以通过说明类型需求在结构上刻画类型,以便使用它们。
原文:The Purpose of Scala's Type System(Martin Odersky访谈录)