Apache 发布 Groovy 2.5 正式版及 3.0 预览版

  • Michael Redlich
  • 无明

2018 年 7 月 12 日

话题:JavaDevOps语言 & 开发架构

Apache 基金会最近发布了Groovy2.5,新功能包括:

  • AST 转换的改进
  • 新的宏支持
  • 其他杂项改进

运行 Groovy 2.5 至少需要 JDK 7,在 JDK 9+ 上运行可以忽略良性警告。

尽管最近人们把关注点转到了其他 JVM 语言上(如 Kotlin),但 Groovy 仍然有很大的增长。正如 Groovy 提交者、OCI首席软件工程师 Paul King 博士在最近的一次网络研讨会上所说的:

Groovy 的下载量说明,它仍然是继 Java 之后 JVM 上第二大最受欢迎的语言,而且这个数字还在不断增加。今年第一季度,下载次数为 9000 万次,比去年第一季度下载次数的两倍还要多。所以我们可以看到,人们仍然对 Groovy 很感兴趣。

在过去的 12 个月里,Groovy 增加了 30 个新的提交者。

AST 转换——注解

如下图所示,为了保证转换之间的一致性,对很多现有的 AST 转换进行了改进,并在 2.5 版本中添加了 11 个新的转换。在 Groovy 3.0 中添加了一个额外的转换,但在 GA 发布之前可能会出现更多转换。



AST 转换——宏

如上所述,Groovy 提供了大量的内置 AST 转换。开发人员也可以创建自己的自定义转换,前提是需要了解 Groovy 语法结构的内部表示。

2.5 版本中的宏功能消除了了解语法结构内部表示的需要,正如发行说明中所定义的那样:

在创建编译时元编程扩展时,宏可以让你直接使用 Groovy 语法,而不是使用内部编译器表示。因此,转换的创建将掌握在所有 Groovy 程序员手中,而不仅仅是 Groovy 编译器创建者。

例如,假设开发人员希望创建一个转换(@Info),用于生成一个方法(@getInfo())。在 2.5 版本之前,需要编写以下代码:

...
def clazz = new MethodCallExpression(new VariableExpression("this"), "getClass", EMPTY_ARGUMENTS)
def body = new ExpressionStatement(new MethodCallExpression(clazz, "getName", EMPTY_ARGUMENTS))
classNode.addMethod('getInfo', ACC_PUBLIC, STRING_TYPE, EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, body)
...

有了宏以后,上面代码中的前两行可以替换为:

def body = macro(true) {
    getClass().name
    }

更多详细信息可以查看发行说明。

Groovy 3.0

Groovy 3.0.0-alpha-3 从 6 月下旬开始就可用,并计划于今年晚些时候推出其他 beta 版,候选版本预计于 2019 年初发布。

Groovy 3.0 至少需要 JDK 8 才能运行,并对 JDK 9 及更高版本的支持进行了改进。一个名为 Parrot Parser 的新解析器将支持新的 Groovy 语法,这是一个重要的新特性。

InfoQ 就最新版本的发布采访了 King。

InfoQ:你能谈谈默认的 Indy 解析器和 Groovy 3.0 的新解析器 Parrot 之间的区别吗?

Paul King:要了解“Indy”和“Parrot”之间的区别,需要了解更多的细节。Groovy 的解析器分多个阶段完成它的工作。早期阶段读取源代码并将其转换为内部抽象语法树(AST)表示,后续阶段将 AST 转换为可在 JVM 上运行的字节码,与从 Java 编译器生成的字节码运行的方式几乎相同。

当我们谈论“Parrot”解析器时,指的是 Groovy 3 中经过完全改进的编译器早期阶段。它经过重新设计,更加灵活,并使用了最新的技术。这方面的工作让 Groovy 能够进行快速演化,这意味着我们可以将 Java 中为“剪切”兼容性而做出的变更与原生 Groovy 变更结合在一起。

当我们谈论“Indy”时,它指的是编译器在后续阶段生成的字节码类型。在 Groovy 2.0 到 2.5 版本中,我们支持生成“经典”版本以及“Indy”版本的 Groovy 字节码。Indy 版本的字节码的生成使用了 JDK 7 中引入的“INvoke DYnamic”字节码指令。尽管这些指令被添加到 JVM 中是出于多种原因,但其中的一个特定用处是用它们提升 Groovy 等动态语言的性能。支持这些字节码指令的 JDK 的早期版本包含了一些错误,虽然某些地方的性能有所提升,但其他地方在使用传统的字节码指令时速度更快,如手动编码的原始类型优化。为此,我们一直支持这两种变体。Groovy 3 编译器的 alpha 版本仍然支持这两个变体,不过我们正在努力将 Indy 变体作为默认的选项,并进行其他的一些优化,争取完全移除旧的变体。

InfoQ:Groovy 中提供了大量内置的 AST 转换,那么开发人员在什么情况下会编写自定义的 AST 转换?

King:AST 转换可以用在很多场景中。可以用它们来移除样板代码、捕获常见的设计模式和编码样式,以及支持声明性编程。我们确实在 Groovy 中捆绑了很多有用的 AST 转换,我们认为它们都是可被广泛应用的转换。在以下这些显而易见的情况下,开发人员需要创建自己的 AST 转换:

  • 如果某些转换有特殊用途,我们不太可能将它包含在 Groovy 中。
  • 如果有人不喜欢内置转换提供的行为,并且无法使用注解属性来自定义行为,那么他们可以试试其他方式。首先,他们可以使用元注解功能将我们注解的组合“捆绑”在一起,也可以将它们与 Spring 注解结合起来。如果这样还不能满足他们的需求,那么就需要自定义一个。
  • 有人可能正在编写特定于其领域的 DSL,并希望在 DSL 中加入注解。这只是编写 DSL 时的一个选项。
  • 有人可能正在编写自己的框架,并希望提供强大的注解,以简化框架用户的编码工作。

举个例子,Grails 光是在 Grails-core 中就使用了大约 20 个 AST 转换,Griffon 也增加了不少 AST 转换。Micronaut 的 AST 转换需要处理超过 100 个注解。

InfoQ:有了新的宏功能,你是否预计会有更多开发人员编写自定义的 AST 转换?

King:毫无疑问,人们需要一些时间熟悉宏。但是,一旦有了一些例子,通常会出现雪球效应。我们必须拭目以待。在任何情况下,我都可以看到我们在 Groovy 代码库中添加了很多内容。

InfoQ:新的 JDK 发布节奏是否会影响 Groovy 开发?

King:是的,更快的发布节奏有一些非常好的方面,但它也给很多开源项目带来了压力。Groovy 尝试运行尽可能多的 JDK 版本。版本越多,就越难做到。不仅我们需要做很多额外的工作,我们还依赖其他开源工具,这些工具必须保持最新,并且在各个版本中保持足够的一致性,这样我们才能够保持兼容。或许 JPMS 对我们的影响更大。它带来的一些变化仍在我们的待办事项列表中,在发布 Groovy 3.0 GA 之前需要修复它们。

InfoQ:是否有计划让 Groovy 3.0 支持 JDK 11?

King:Groovy 3.0 已经非正式地支持 JDK11。它可以使用最近的 JDK11 EA 版本进行构建,一些测试套件也运行良好。就 Java 源代码兼容性而言,我们已经支持在局部变量 lambda 参数(JEP 323)中使用 var 作为 def 的别名,所以即使是在 JDK 8 上运行,你也可以在 Groovy 中定义 lambda,如下所示:

InfoQ:关于 Groovy 2.5 和即将推出的 Groovy 3.0,你还有什么东西想要与读者分享的?

King:我们对 Groovy 使用量的持续增长感到非常兴奋,我们希望在未来版本的 Groovy 中引入更多东西。我们非常感谢 Groovy 社区,他们在完成路线图中计划的所有功能以及在进行一些重大的错误修复时表现出了极大的耐心。

因此,虽然我们仍然面临着一些工程挑战,但我们看到了 Groovy 美好的未来。我们非常欢迎任何想要加入并帮助我们或参与邮件列表讨论的人。

InfoQ:你目前的职责是什么,也就是说,你每天的工作是什么?

King:我的大部分时间都花在 Groovy 上,参与邮件列表和其他论坛的讨论,或者为代码库做贡献,或者为使用 Groovy 的其他项目提供支持。

其他资源:

查看英文原文Apache Releases Groovy 2.5 and Preview of Groovy 3.0

JavaDevOps语言 & 开发架构