Java Champion Dick Wall 谈 Scala 的优点(第 2 部分)

作者:Janice J. Heiss

2012 年 5 月发布

本系列访谈聚焦获得业界、学术界、Java 用户群以及更大社区中 Java 开发人员特别认可的 Java Champion

Dick Wall
Dick Wall

Dick Wall 是一位拥有 15 年以上经验的 Java 程序员,他最开始使用 Symantec Cafe 在 Mac 上编写 Java 小程序。他曾参与能源配送系统的大型模拟工作和地理信息系统开发,并在 Google 积极倡导使用 Android。目前,他在 Locus Development 使用 Scala 研究人类基因。他还与 Bill Venners 合作在 Escalate Software 提供 Scala 培训和咨询,目前他几乎只使用 Scala。此外,他还创办并与他人共同主持广受欢迎的 Java Posse 随身播,并领导硅谷湾区的 Scala 爱好者 (BASE) 活动。

第 1 部分,Wall 提供了 Java Posse 的一些内幕消息,探讨了基因洞察对于人体健康的潜力,并与大家分享了他对于 JVM 替代语言的见解。下面我们介绍他使用 Scala 的经历。

Oracle 技术网:是什么让你将如此多的精力奉献给 Scala 这种相对不为人所知、受欢迎程度在 Tiobe 排行榜仅排在 51 到 100 之间的语言?

Wall:转为使用 Scala 的过程比较漫长。但该语言几乎包含我认为语言中应包括的一起要素。我很小的时候就自学了 BASIC。当时父母给我买了一台计算机(我们在学校也有计算机用)。在大学,我学习了更全面的语言,如 Pascal、Forth 和 C(跟着是 C++)。我还用过一些函数语言,如 Lisp 和 Miranda。我记得曾对 Miranda 感兴趣但最终发现它过于学术性、令人生畏且不切实际,因此最终放弃了它。Lisp 我继续使用了好多年(主要是 Emacs 中嵌入的 eLisp 形式),直到我得出结论认为 Lisp 与其说是一种语言不如说是一种语言构建工具包。所有开发人员都在其基础上按照自己设想的理想语言创建新的语言,因此你永远不会真正掌握 Lisp — 每个新项目的时间都花在学习不同程序员所构造的一个全新的 Lisp 方言上了。

最后,从用实用角度考虑,我选择了 C(更经常使用的是 C++)作为主要使用的开发语言。我刚开始从事的就是跟 C++ 编程相关的工作。但问题是 C++ 变得越来越复杂。Pascal(有时甚至是 BASIC)的许多简单性、优雅和开发速度都不见了,并且随着时间的推移问题越来越严重。

在上世纪 90 年代早期,我发现了两种新语言:Python 和 Java。二者中我更喜欢 Python。虽然它同时提供了简单性和工作效率,但还是有些问题。执行可能会很慢,工具支持不太好,并且缺少标准的图形 UI 系统。迄今为止,在 Python 和 Java 之间,我仍然喜欢用 Python 来执行任何要求速度快的任务(尤其是文件、数据库或 XML 处理),我经常编写 Python 脚本而不是 shell 脚本来自动执行任务。

Java 变成了一种折衷语言,但还算是一种好语言,并作为我的职业语言长达 15 年以上。它比 C++ 简单,性能(尤其是在 JDK 1.2+ 版中)可以接受(在最近版本中甚至很快),并在业界获得广泛认可。

“我很高兴地发现 Scala 是一种实用语言,它提供了许多我从 Miranda 这样的函数语言上用过(并且喜爱)的特性。我发现了一种我认为十全十美的语言。”

Dick Wall
Java Champion

但 Java(语言)有其自己的不足,并已经累积了许多年。不顾条件的向后兼容付出的成本实在是太大了。更新的语言(如 Microsoft 的 C#)展示了像 Java 这样的语言的可能趋势,但 Java 已经有一段时间没有增加任何有雄心的特性了。尽管它仍然是一种很好的折衷语言(跟以前一样好),但我们现在有了其他选择 — 其中许多是由其竞争对手(如 .NET)推出的。

我一直在留心寻找一种能够同时提供 Python 那样的工作效率和简单性的语言来编写些东西并快速投入使用,同时还提供强大的性能、可工具化以及类型安全(这些都是我喜欢的 Java 特性)。Scala 就是第一种在一个软件包中提供所有这些特性的语言,非常适合我。在 Scala 中编程,感觉类似于在 Python 中编程(只要能想到,你就能做到),但还有一个优点,即让编译器来对你进行监督,告诉你这里有错误的类型,或者是那里方法名不对。

最终的“啊哈!”时刻是在大约一年半以前。当时我有一个要快速完成的任务,开始我是用 Python 编写(正如之前许多年来一样),但随后意识到用 Scala 可能也可以写得同样快。我尝试了,确实如此,用它写得差不多一样快。这部分是由于我一直使用 Scala,对它比较熟悉,但是这也说明使用静态类型的语言可以具有与使用动态类型的净室语言(例如 Python)相同的工作效率。

我很高兴地发现 Scala 是一种实用语言,它提供了许多我从 Miranda 这样的函数语言上用过(并且喜爱)的特性。感觉似乎我的职业编程历程终得圆满了。我发现了一种我认为十全十美的语言。

Scala 目前仍相对不为人所知,但已经获得许多关注,并已经有一些有实力的支持者。我认为它将继续提升其受欢迎的程度,我对其未来并不担心。

给 JVM 带来了很大压力

Oracle 技术网:你曾写道:“Scala 给 JVM 带来了很大压力,可能比任何其他主流语言带来的压力更大(尤其是考虑到类型系统时),这使其成为一种理想的试金石,可以通过它来检验 JVM 如何处理刚创建时想都想不到的任务。这听起来像一个诊断点。Java 开发人员会如何利用它呢?

“以我的经验,Scala 给 JVM 带来的压力比我见过的其他 JVM 语言都要大。Scala 试图在各方面都超越 Java”

Dick Wall
Java Champion

Wall:JVM 起初用来支持用 Java 编写的代码,且其特性集反映了该主要语言的需要。在实现一种在 JVM 上运行的替代语言时,设计师经常需要围绕这些缺失的特性找到创造性的方法。

以我的经验,Scala 给 JVM 带来的压力比我见过的其他 JVM 语言都要大。Scala 试图在各方面都超越 Java。它更面向对象、更函数化、更偏向静态类型、更灵活且更简洁,在许多其他方面,它提供了更多可能。在此过程中,虽然它突显了 JVM 的一些缺点(尽管不像你想像的那么多),但令人敬佩的 JVM 在大多数方面保持得不错。

下面是一些示例:

Trait — Scala 提供了 trait。你可以将其理解为接口(Java 中也有),但 trait 提供了状态和行为(Java 则不能)。结果就是有编译器必须耍一些小聪明,在编译时一起将使用 trait 的类编织到一起,而不必依赖于 JVM 的支持。在实践中这样做效果很好,但这意味着如果 trait 发生了变化(新的 Scala 库版本中经常会发生变化),将破坏这些库的二进制兼容性。这导致新的 Scala 版本经常需要为该新版本重新编译库的问题。

类型安全的清除 — 由于 Java 向后兼容的原因,通用类型安全由编译器处理,并在 JVM 获得通用容器对象之前丢弃。这在 Scala 中比在 Java 中表现得更明显,主要是因为 Scala 的类型系统更高级,并且因为 Scala 有一个称为模式匹配的特性使它能够轻松区分代码中的字符串列表和整数列表,但这在 JVM 中实际上不可能,因为丢失了内部类型信息。

消除尾调用递归 — 函数语言使用递归作为一种避免可变状态的技术,许多函数语言可以做到这一点而无任何副作用(它们在运行时将尾调用转换为循环,因此您不必承担与降级执行堆栈相关的开销或风险)。遗憾的是,JVM 不能自行完成这一任务。Scala 进行了尝试但经常要在编译时处理不完整的信息(例如,它不知道其他类会怎样扩展它正在编译的类),因此可能会错失消除尾调用的机会。

但整体来说,对于一个并非设计用于支持其运行的语言来说,JVM 表现得相当不错了。

Scala 并不比 Java 复杂

Oracle 技术网:Scala 是不是比 Java 更复杂?

Wall:哦,这是一个很大的问题,无法直接回答。我认为在 Scala 中编程可以与在 Java 中编程一样简单或者更简单,而且其代码可能更易读、更简洁、更易于理解。它还可以提供更大的灵活性和范围以便为许多任务实现更好的解决方案。至少有些声称 Scala 语言很复杂的情形更多的是因为不熟悉该语言(与流行的语言如 Java 相比),而不是因为对于语言复杂性的技术考虑。因此就说 Scala 比 Java 更复杂?答案当然“否”了。

我建议人们研究一下 Kojo 项目,看看 Scala 可以是多么的简单。

这并不是说它总是很简单。与 Java 相比,Scala 提供了更大的灵活性和更多功能,如果你要运用所有这种灵活性和功能,则需要了解比 Java 语言更多的知识。例如,Scala 允许开发人员使用编译器插件扩展实际编译器,这涉及操纵编译器创建的抽象语法树 — 这非常复杂。但并不是所有人都要这样做才能使用 Scala。

作为开发人员,我们的大部分任务正变得越来越复杂。如果他们不这样,进度肯定要出问题。多年前我开始编程的时候,程序都是通过文本界面与人交互,大多数程序无需考虑多线程并行执行,程序平均大小小于 100 KB。现在我开发的系统都使用 Web UI 交互;有多个 Web 服务、数据库和数据源;以及在有若干 GB 内存和多个核的计算机上运行更大、更复杂的数据。

假设给定项目的复杂度提高到一定高度,我会选择使用使我尽可能接近该复杂度的一种语言和一组库,以便我们只需要操心最后那一小段差距就可以了。使用 Java 则在复杂度上会留下相当大的差距。虽然加入像 Wicket 或 Camel 这样的库可以帮助更多地缩小该差距(但我还是要说有些库的学习曲线完全与 Scala 更高级特性的学习曲线一样高),而最终你仍将不得不艰难弥补最后一小段差距。

Escalate Software

Oracle 技术网:你与 Bill Venners 合作通过你们的公司 Escalate Software 向开发人员教授 Scala。你们都提供什么培训?

Wall:Bill 和我理所当然地成为 Scala 的早期采用者,并且都是自学的。我们花了很长时间来选择语言(尤其是来自 Java 的语言),培训旨在加速他人的学习体验,使其更容易上手。同时,我发现当我在 Google 任职开发倡导者时我喜欢教授,尽管我不想全职做这个。Bill 也是一个天生的老师,因此我们尝试做这个是很自然的事情。

我们提供 Scala 的零起点培训。我们假设学员在学习我们的“应用基础”课程(该课程一共三天时间)之前完全不了解 Scala,而且有许多上机操作实践(学员一半时间用于学习 Scala,一半时间用于用它来编程),使开发人员提高到能够在实际项目中使用 Scala 和标准库的级别。该课程还包括 Scala IDE(培训中我们主要讲解 IntelliJ,但这些技能也适用于其他 IDE)。该课程的唯一要求是要有点编程语言技能。我们的课程特别针对有类似 Java 语言(例如 Java 和 C#)技能的人,但我们成功培训了许多不同语言的程序员,包括 Smalltalk、Ruby、Python 和 Perl 程序员。尽管函数编程技巧是重点,因为这有望成为参加该课程的大多数程序员的新技能集,但我们也讲授 Scala 的面向对象特性。

现在我们在这两天的应用基础课程后面添加了一个高级课程,学时也是两天,并假设学员有 Scala 的实践经验。学员可以任选一门课程,也可以选择一个星期内学完两门课程。

Scala 比 Java 更有效率

Oracle 技术网:在 Escalate Software 现场,你们说:“Scala 开发人员通常会发现一旦跨越初期的学习障碍,则其在大型项目中的工作效率比使用 Java 时高出数倍,而我们可以帮助他们克服这个障碍”。这是一个非常强有力的承诺。这么有信心的底气从哪里来的?

“我可以发誓说我使用 Scala 的工作效率比我使用 Java 时高很多。除非另有原因,我不知道我所认识的许多使用 Scala 的人怎么不会这么认为。”

Dick Wall
Java Champion

Wall:这个承诺部分来自于自己的经验,部分来自于与其他 Scala 开发人员的交谈(我从社区工作中认识了许多这样的开发人员)。以我个人的经验,我现在用 Scala 和用 Python(我以前工作效率最高的语言)的工作效率一样高,这意味着对于较复杂的项目,我可以三倍于用 Java 做相同项目的速度交付。曾经与我交谈过的其他 Scala 开发人员都声称,在开始使用该语言的一到两个月内,他们使用 Scala 的工作效率开始与使用 Java 时一样高了,并且还在迅速提高。当然,总有些人会对这些声明提出质疑,但我可以发誓说我使用 Scala 的工作效率比我使用 Java 时高很多。除非另有原因,我不知道我所认识的许多使用 Scala 的人怎么不会这么认为。”

下面是 Scala 提升性能的一些主要特性:

函数编程特性 — 函数字面值、闭包、模式匹配、递归以及其他易于获得的语言特性提高了工作效率。问问用过带闭包的语言的人他们在 Java 中有多想念该特性,你可能会得到各式各样的答案。

样板破坏者 — Case 类、trait及其他高级特性均可消除在代码中其他地方重复操作的需要。你只有使用过带 trait 的语言,才能领略静态类型的语言中重构的全部功能。Case 类还消除了值对象的所有干扰(像 equals 和 hashCode 实现),并同时减少了常见错误来源。

代码简明 — 我的 Escalate 合作伙伴 Bill Venners 喜欢引用《Strunk & White》中的“最有活力的写作就是简明”,意思是说信息而不是形式才是最重要的。Java 在其编码过程中有大量的形式 — Scala 则更侧重于信息。

对于像 Groovy、Python 和 Ruby 这样的动态类型语言,亦是如此。差别在于 Scala 还有编译器(或者经常是 IDE),它不时拍拍你的肩膀,告诉你“出错了”,而不是任其在测试或运行时失败。这是另一种大大节省时间的方式。

Oracle 技术网:你声称“Scala 也可以使用所有 Java 库和框架,甚至可以使用现有的项目代码,并且通常还能改进其 API”。你能否用几个例子来说明它是如何改进某些 API 的?

Wall:Scala 运行在 JVM 上,且几乎在各方面都是 Java 特性集的一个超集。这意味着你在 Java 中可以用的任何库在 Scala 中都可以使用,尽管有时没有这个必要。

Scala 有一些 Java 没有的特性,如函数字面量和 trait,并且这些特性可以实现更强大的 API 来使用库。对于广泛使用的库常见的一个操作就是开发人员将 Java 库与一个轻量型的 Scala 包装器封装在一起,这样就可以让你使用其中某些特性来使 API 更简明。也许最有分量的一个示例是包含在 Scala 2.9 中的并行集合,它在后台使用来自 JSR 166 的并行数组和分解/合并工作,但其 API 远远更小、更简单。其他示例有经常被扩展来使用闭包作为事件处理程序的 GUI 库(例如 Scala Swing)等。这些适配器可以非常的小,但可带来工作效率和简单性方面相当大的提升。例如,这里的一些示例所示。

SubCut:开源生物信息

Oracle 技术网:您有没有什么开源项目愿意与 Java 开发人员分享?

Wall:有一个名为 SubCut 的开源项目。用 Scala 编写的依赖注入与服务位置之间的一种交叉,它是专为 Locus Development 编写的,但我认为它很有用,值得公开它的源代码。今后我们希望开发更多开源项目,但我们做的许多工作主要是针对一些具体问题的,可能对其他人用处不大。也就是说,我想我们将为许多其他开源生物信息项目做些贡献。

另请参见

第一部分:Java Champion Dick Wall 谈基因研究、Java Posse 和 JVM 的替代语言

Dick Wall 的博客

Escalate Software

Java Posse

SubCut

Java Champion

Java 用户群

Tiobe 排行榜

Kojo 项目