BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Scala 2.12将只支持Java 8

| 作者 Ben Evans 关注 30 他的粉丝 ,译者 潘瑾瑜 关注 0 他的粉丝 发布于 2014年8月15日. 估计阅读时间: 13 分钟 | QCon上海2018 关注大数据平台技术选型、搭建、系统迁移和优化的经验。

根据近期Scala路线图所公布的信息来看,Scala从版本2.12开始,只能运行在Java 8及之后的版本上。InfoQ找到了Adriaan Moors(Typesafe的Scala技术主管)和Json Zaugg(Typesafe工程师),了解到更多关于这个改动的内容,以及Scala将如何利用Java 8的lambda表达式的细节。

InfoQ:做出这个改动的最大驱动力是什么?

Adriaan:使用Java平台已经给Scala的成功和快速采用带来了帮助。我们热衷于和平台一起逐步发展,享受平台和平台生态系统带来的改进。对lambda表达式的原生支持使得Java 8的虚拟机成为了Scala更好的宿主。

InfoQ:当进行改动时,你认为最大的挑战可能是什么?

Adriaan:迁移到Java 8对于我们来说是一个很自然的演进。例如,Scala 2.11已经有一个试验性的特性,这个特性是在Java 6上尽可能多地模仿Java 8提供的一些功能。

根据以往的实现,一个Scala的函数体会被提取到外部所在类的一个私有方法中。为了在运行时表示这个函数,会实例化一个匿名类。而这个类会包含一个方法,用于调用上述私有方法。通过迁移到Java 8,我们不再需要在编译期生成这个匿名类,而是在运行时使用LambdaMetaFactory取而代之。类似地,2.11的类型检查器支持从Scala的函数代码中合成单一抽象方法(Single Abstract Method)类(当使用参数-Xexperimental运行)。

这些是这个挑战的技术层面的亮点。正如你对一个平台变动的期望,社会层面也是一个非常重要的因素。2.12的每一点的计划都围绕如何使升级变得容易。并且我们对社区抱有热切的期望。是否能快速采用Scala 2.12取决于围绕它的核心类库、测试框架、IDE支持和其他工具的可用性。另外,我们意识到不是所有人都能立即升级到Java 8。为了解决这个问题,我们计划把2.11和2.12在语言和类库上的差别控制在有限的范围内。我们想要开源作者们能够非常容易地交叉编译这两个版本。 这也是在更长一段时期内,要将2.11作为一个可用版本的一部分重要原因。关于我们打算如何执行这个策略,2.12的路线图包含了更多的细节。

InfoQ:从最初发表的博客来看,由于触及到很多Scala子系统,这是个相当大的变动。你认为需要多大规模的团队才能完成这个变动?

Adriaan:很难用数字来表示“Scala团队”的人数。和往常一样,社区将完成其中一部分重要的工作。一些Typesafe的工程师正在做Scala支持Java 8的工作。具体来说,Jason Zaugg正在处理Java 8提供的lambda表达式;Lukas Rytz正在跟进Miguel Garcia启动的工作,改工作是关于基于新的ASM的后台编译器和优化器的。所有的工作自然会贯穿于整个公司:Akka和Play有易用的Java 8 API,并且我们会不断改进它们。Scala IDE和sbt已经支持Java 8,我们的其他产品也同样支持。

InfoQ:Scala具有Java 8的一些基本功能已经有一段时间了。在语义上Scala和Java 8是否存在着一些差别?你认为采用JDK 8进行开发时会遇到什么问题?

Jason:在一些少见的用例中,JDK8中LambdaMetaFactory的语义并不能直接为我们工作。比如,它不知道如何对我们的Value类进行装/拆箱操作,或者如何通过BoxedUnit将一个返回值为空的方法句柄转换成FunctionN::apply的通用返回类型。但是,我们有一些选择来适应这些限制:在一些用例中,我们可以选择坚持使用当前的匿名类编码方式,或者我们可以生成访问器方法用以执行所需的装箱操作。根据原语生成正确的、指定版本的代码是一个需要认真对待的工作。但是,我们已经完成了这些挑战的解决方案的原型,并且非常确信不会有明显的障碍。

我们也计划利用默认的方法来编译trait(Scala中多重继承的轻量级形式)。这种编码方式将有更多的限制:当trait中方法覆盖了一个类中的某个方法时,trait将无法正常工作;支持的字段也有这方面的限制。默认的方法在设计时并没有考虑到Scala这个应用,但它是设计二进制兼容性的重要资产。未来的JDK版本或许会提供更强大的工具;Brian Goetz最近起草了关于classdynamic的建议,听起来对Scala有极大的好处。

InfoQ:对JDK8的lambda表达式子系统的整体设计有什么额外的评价吗?

Jason:JDK中lambda表达式的实现看起来有着良好的构思,并得到了很好的执行。设计的关键是invokedynamic(用于推迟处理编码的细节)的使用。这又是建立在invokedynamic本身前瞻性的规范上,它已经被测试证明是一个很强大的API:已经多种方式成功地使用了该API,这是连API作者都没有预见到的!即便如此,就lambda表达式通过Java语言所暴露出来的方式,对于Scala来说,还是有些不同的权衡的。最明显的不同就是使用Functional接口,而不是一个标准的拥有不同参数数量的Function泛型类型集合。这本身并不是坏事:为了支持Functional接口,我们也正在扩展我们的Function类。但是选择手动规范这些函数接口看起来在一定程度上是有特定目的的,不过这让编写通用代码变得更加困难。

InfoQ:Java 8明显地引进了一些基本的函数式编程风格的语句(map,filter等)。对于Scala来说,你认为这是一个威胁还是一个机会,或者说这是否会增加Scala开发者的数量?

Adriann:对于Scala来说,我完全相信这是一个非常好的机会。函数式编程不仅只是关于函数字面上的轻量级语义和多态方法调用时的一些类型推断。这只是个开始。对我而言,函数式编程是一个能通过构造合适大小的抽象来构建和理解程序的过程。Scala提供了函数式编程的所有东西:从构造和定义单一方法的抽象(functions),到多个连贯一致的类(traits)。对我而言,一门(静态类型)函数式编程语言是:

1)专注于构造短小、易于理解的功能单元。函数易于理解,因为它们只依赖于它们的参数。函数的类型和用于组合函数的组合器的类型刻画出了程序的高层结构。类型如同高科技管道:正确地引导数据至关重要,而容纳数据的结构上的改变不会对数据的处理造成阻碍。只有将管道隐藏在语言之下,这才能成真。Scala强大的本地类型推断对于简单地使用一个函数式编程库起着至关重要的作用,因为这些库倾向于充分利用泛型。Java 8有限的类型推断能够通过IDE的支持得到加强。但是,会导致要维护IDE生成类型的样板代码的老问题。

2)具有一个可以让类库设计者简洁地表达这些安全的高阶抽象的类型系统。Scala长期支持高阶的参数多态机制(“高种类的类型(higher-kinded types)”或者“类型构造器多态机制”),以及ad-hoc多态机制。Java的泛型是第一阶的,并且重载是ad-hoc多态机制的一种极其有限的形式。相比获得的益处,这种形式带来了更多的痛苦。

3)鼓励不变性。具有不可变性的代码通常更易于理解。当然,使用Akka对于扩展你的应用(使用机器的所有CPU或者跨数据中心)和排除故障是有显而易见的好处的。具体来说,可变性经常使得诊断你代码变中不同部分的牵连关系变得困难。Scala也是非常务实的:有意地让val和var只有一个字母的差别(尽管Scala IDE将可变性变量高亮成红色)。

4)根据数据的模式匹配定义函数(并且确保所有的场景都被覆盖),用不断演进的操作看待一个固定的数据模型;对于仅关注不变的功能和不断演进数据模型的OOP(请参考访问者模式),Scala进行了补充和深度地集成。

InfoQ:最后,我们的一个编辑有些无法接受2.12是一个大版本的事实。Scala 3是否会有一些大的变化?

Adriaan:我们将要求使用者采取行动的升级分为两类:一类只需要重新编译(这类具有源码兼容性,但不具有二进制兼容性);另一类需要牵涉更多的工作,要求对源代码进行改动。我们保留了版本号中最有意义的部分(epoch)用于后一类的升级。这类升级很“罕见”(比如,每10年1次)。大约每18个月,我们会发布一个新的大版本。版本号的中间数值会增加。为确保平滑升级,相同的代码应该不需要修改就能够使用相邻的大版本进行编译-前提是“不赞成使用”警告(deprecation warnings)已经被处理。在我们的处理流程中,“不赞成使用”是个非常重要的部分:我们尽力(谨慎地)平衡稳定性和语言演进,不会轻易地破坏你的代码。但是我们确信,一种健康的,有节奏的创新将使每个人都受益。

最后,Scala小版本的随意替换对于程序应该是无差别的,它们应该是向前和向后二进制兼容的。它们的发布节奏是多变的:在发布生命周期的早期,可能每隔一个月都会有一个小版本。随着我们把开发重心转移到下一个大版本,小版本的发布将减缓到每季度一次。

路线图中已讲明,我们计划使2.11和2.12两个大版本间的交叉构建至少像2.10和2.11间的交叉构建一样简单。当我们要在Scala 3中打破源码兼容性时,我们将会非常谨慎的处理,并且要有好的理由,比如使语言变得简洁,提高编译器的速度。

当从Scala x.y.z升级到(x+1).y.z,你很可能需要修改源代码或者使用一个工具替你完成这个工作。当从x.y.z升级到x.(y+1).z,在处理好源代码中的“不赞成使用”警告之后,你只需要重新编译源代码。因为“不赞成使用”的部分有可能在新版本中已经被删除了。最后,Scala x.y.a和x.y.b应该能够替换使用。

被采访者

Adriann Moors 在Typesafe领导Scala团队。他从2006年开始使用Scala编程。当时他正在试验泛型编程,这充分利用了类型构造器的多态机制。 在Scala实习期间,他在Scala 2.5中实现了这个特性(这使他成为Scala类型检查器的第一个外界贡献者)。毕业之后,Adriaan作为一名博士后加入了Scala团队,专注于Scala的理论基础和实现(方法类型依赖和隐式搜索,类型构造器推断,2.10中新的模式匹配器)。

Jason Zaugg是Tpyesafe的Scala团队中的一名软件工程师。过去6年里,他一直在企业项目和开源项目中使用Scala编写代码。目前专注于推动Scala平台的发展。

参考英文原文:Article: Scala 2.12 Will Only Support Java 8


感谢赵震一对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ)或者腾讯微博(@InfoQ)关注我们,并与我们的编辑和其他读者朋友交流。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

性能? by He henix

一直不太能理解的是,invokedynamic 跟以前的实现方法(可能是 invokevirtual)相比,不会导致性能下降吗?毕竟是动态类型的东西

性能? by He henix

一直不太能理解的是,invokedynamic 跟以前的实现方法(可能是 invokevirtual)相比,不会导致性能下降吗?毕竟是动态类型的东西

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

2 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT