JVM的动态语言支持:为新一代流行语言铺平道路
Java SE 6已不再局限于Java语言了,因为SE 6还可以用来执行动态脚本语言代码。据Sun公司Java SE平台项目的负责人丹尼・考沃德(Danny Coward)称,Java虚拟机要成为所有动态语言的最佳执行平台,而提供脚本语言支持只是实现这一计划的第一步。2006年12月11 日,Artima记者弗兰克・索莫斯(Frank Sommers)就JSR 292――支持Java 平台上的动态语言特约采访了考沃德。
Java SE 6可以加入对Java平台脚本JSR 223的实现,从而可以被用来执行以Ruby、Python、Groovy或者JavaScript等动态语言编写的脚本语言代码。但是,丹尼・考沃德认为, Java虚拟机是专门为静态语言而设计的,要在这样一个平台上实现动态语言解释器绝非易事。考沃德是Sun公司Java SE平台项目的负责人、JSR 292规范的主要制订者。
在Sun即将发布Java SE 6之前,Artima记者和考沃德进行了一次访谈,其中谈到了Java虚拟机动态语言支持的未来、invokedynamic――一个专用来设计对动态语言对象的支持的新JVM 指令、运行时改变或添加类方法的hot-swapping,以及将Java虚拟机变为动态语言实现理想平台的目标。
弗兰克・索莫斯 : Java SE 6最大的特征之一就是对动态语言的支持。您能向我们描述一下在现有的Java SE版本中,这一目标将得到怎样的实现?今后还会增加哪些对动态语言的支持?
丹尼・考沃德: 在过去的几年里,我们已经注意到了一种现象。和.NET开发者社区不同,Java开发者社区早已经开始体验动态语言了。动态语言逐渐成为许多开发者 Java应用开发日常工作的一部分,并常常用于原型开发(prototyping)或用来提高开发速度。为了快速得到更大规模的(Java)应用程序,人们一直在使用动态语言胶合程序部件。
今天,Java平台的脚本JSR 223将与Java SE 6一起发布。在聚集动态语言爱好者这一方面,JSR 223迈出了它的第一步。首先,它为开发者提供了允许将其它语言的代码与Java代码混合起来的API。其次,JSR 223还是一个框架,它允许开发者插入用来解释动态语言的脚本引擎。在Java SE 6中,我们增加了Rhino JavaScript引擎,这样非传统的开发人员也可以使用JavaScript。
开发者也可以使用脚本引擎的框架来插入自己的解释器引擎。我们已经从scripting.dev.java.net 上的java.net脚本项目中收集了二十多种动态语言引擎。这是Java对脚本语言支持的第一阶段,今天我们已经实现交付了。
JSR 292――支持Java 平台上的动态语言是对JSR 223的合理跟进。Java是一门静态类型的语言。Java中的字节码需要知道返回类型是什么以及方法调用的参数类型是什么。
开发者在为动态类型语言写解释器引擎时,不得不硬造出很多Java类型,以便满足Java字节码方法调用的需求。这使得这些解释器很脆弱:代码一旦被人改变,要加入并重新设计所有这些硬造出来的类型将很难。而且,它还会降低执行的速度。有趣的是,Java虚拟机并不需要静态地确定那些类型是什么,只有字节码才要求这样。
在JSR 292中,我们将提供一个新的字节码――invokedynamic。这为Java虚拟机提供了一个方法调用的指令,而无需知道字节码的返回值和方法参数。这是一个很技术、很官方的解释,但是它能够加速Java虚拟机上的解释器实现,并使它们变得更加健壮。
弗兰克・索莫斯:您刚才提到invokedynamic将加快动态语言解释器的执行速度。您能举个例子吗?
丹尼・考沃德:假如你现在要获取一个确定大小的集合(collection),方法的返回类型是Collection。例如,在JRuby中,那种方法可能不需要一个特定的类型返回值就可以得到实现。开发人员可以这样理解,将要返回的是一个集合,但是并没有一个特定的返回(值),因为(Ruby)不是一个静态类型的语言。
动态语言引擎的创造者们在将Ruby代码转化为Java字节码。如果今天的JRuby引擎要将那种方法调用转化成字节码,将不得不创建一个合成接口来表现返回类型。这个接口不是由开发人员创建的,而完全是由JRuby引擎创建的,这样JRuby引擎就可以实现那个方法调用并将它返回成字节码。这只是返回类型,方法参数和异常的情况是一样的。
JSR 292则不需要合成接口所需的条件。今天,即便在解释一段Ruby代码时,动态语言解释器的重要性也超出了methodinvoke字节码。有了 JSR292,他们或许很快就可以使用invokedynamic版本。这将使得引擎实现过程流线化,因为今天的很多引擎都在为硬造新的类型和大量的簿记工作而发愁――如果一个方法在七八个不同的地方被调用,那么在所有的地方将不得不重用那一个硬造的类型。
有趣的是,这不是语言的特征,而是字节码的特性。Java开发者决不会有意识地去使用JSR 292的一个新特性,因为JSR 292不是一件公开进行的事情。对于新增的字节码,最令人兴奋的地方在于它是第一个不用于Java语言的字节码。我们打算只将这一字节码加入Ruby、 Groovy、BeanShell以及Python等语言中。我们非常希望这些语言能够在Java虚拟机上得到更快的运行。
弗兰克・索莫斯:那么新增的字节码能够在当前版本的Java虚拟机上工作吗?
丹尼・考沃德:JSR 292的另一方面是调查hot swapping。在很多动态语言中,方法可以在运行时被改变,甚至被添加到一个类。这也是Smalltalk编程最基本的需要。这一想法就是能够在运行时调整类。
JSR 292是在今年早些时候开始的,我们还不确定它的工作效果如何。不过,这是专家们需要去考虑的问题,这还可能有利于动态解释器的性能改进。这一特性可能需要对Java虚拟机做一些调整,Java虚拟机也将因此需要做一些变化。专家们还需要注意安全的问题。当然,我们不会在平台上开放所有的安全漏洞。
弗兰克・索莫斯:您刚才说到了动态语言的很多优点,那么Java以后会不会变成一种更加动态的语言呢?
丹尼・考沃德:将Java变成一门动态语言,这将是一件很有意思的事情。不过,Java作为一门静态语言,它拥有很多优势,如程序的健壮性、可维护性、以及便于向他人发布API的特性。这些优势都是静态语言所提供的,我们不想去改变这些。相反,如果能够让其他的语言在Java虚拟机上得到更好的运行,那么我们就更没有必要去改变Java语言了。
我们依然认为,Java语言是用来开发生命力强、可维护且可分享的应用代码的最佳语言。企业开发的应用软件需要维持很长一段时间,且部分代码需要在不同的开发团队之间甚至在整个社区中分享。对于这些应用软件,Java自身的特性如静态类型特征、我们正在研究的模块性以及包装结构等,都成就了Java 语言创造出具有顽强生命力的健壮程序。
我们看到,动态语言的使用在设计重心上有些不同,至少程序的部分代码运行得很快。在这些情况下,能否与其他人共享代码或能否在时隔六个月之后依然读懂一段代码就不再那么重要了。相反,能否快速地生成代码并迅速写成一个demo或通过Web再现则变得更加重要了。
我们允许Java开发人员使用动态语言进行部分编程,然后将这部分代码转换成Java,或继续用Java来开发程序中更为健壮、生命力更强的部分,其他代码则可以通过更加动态的语言来进行开发。这也是JSR 223的重要性所在。在当今社区中,开发者都有不同的语言偏向和爱好。既然如此,他们为什么不可以同时使用Java和Ruby两种语言呢?
而且,Java发展已过10年,我们对Java所做的变化非常少。我们很清楚,为Java语言增加一些新特性以满足开发者社区可能出现的每一个需求,这是我们很有可能办到的事情。但是,如果我们那样做的话,我们只会使Java变成一门非常复杂的语言,重蹈C++的覆辙。我觉得C++更加注重的是语言的特性而不是简洁性。
弗兰克・索莫斯:您说到要使Java虚拟机成为动态语言implementor的理想执行环境,对此您有多大把握?您是否认为Java虚拟机有什么限制因素会阻碍这一任务的实现?
丹尼・考沃德:现在主要的问题是字节码,因为你不得不硬造出很多类型。这也是JSR 292显得重要的原因。
当然,从理论上来说,Java虚拟机能成为任何语言解释器的宿主。很多事情都可能发生,理论是好的,但是实践更好。关键在于让动态语言能够在Java虚拟机上真正实现飞快的运行。这也是我们正在努力做的事情。
现在,我们不妨换个角度来看你的问题,比如说如果你是一个动态语言设计师或implementor,你为什么不愿意把Java虚拟机作为您的主要执行平台?我们已经在这样一个跨平台、可扩展的运行时环境上倾注了11年的时间和精力。现在,我们的平台在行业内得到了广泛的应用。如果你要创造一门新的动态脚本语言,为什么不选用这样一个理想的实现平台呢?难道还有什么比它更好的运行时环境吗?