Ceylon:真正的进步抑或只是另一种语言?

适用于大众的、面向对象的函数式编程

在计算机语言的发展史上,有很多语言号称“将成为以后的主流语言”。尽管许多利基 (niche) 语言在脚本或特殊的应用程序中得到了一定的应用,但是 C(及其衍生语言)和 Java 语言很难被取代。不过,Red Hat 的 Ceylon 看起来是一种有趣的语言特性组合。它使用著名的 C 风格语法,但是支持面向对象的一些有用的函数特性,而且强调代码的简洁性。让我们来研究一下研究 Ceylon,看看这种未来的 VM 语言是否能在企业软件开发领域占据一席之地。

M. Tim Jones, 平台架构师, Intel

作者照片 - M. Tim JonesM. Tim Jones 是一名嵌入式固件架构师,他是 Artificial Intelligence: A Systems ApproachGNU/Linux Application Programming (现在已经是第 2 版)、AI Application Programming (第 2 版)和 BSD Sockets Programming from a Multilanguage Perspective 等书的作者。他的工程背景非常广泛,从同步宇宙飞船的内核开发到嵌入式系统架构开发,再到网络协议的开发。Tim 在 Intel 工作,住在科罗拉多州 Longmont。



2011 年 7 月 20 日

Linux 和开放源码常常与语言设计的最新成果密切相关。原因可能是支持语言开发的众多工具或平台的开放性促进了语言设计的发展,也可能是基于开放源码技术的开放语言(比如 GNU Compiler Collection 系列、Ruby、Python 和 Perl)非常出色,吸引了开发人员,并鼓励他们进行试验和应用(更不用提 Ceylon 背后是强大的 Red Hat)。无论由于什么原因,Linux 开发人员都可以使用许多种语言,从很少有人使用的陈旧语言直到最新的尖端语言。

Ceylon 不是 Java

“Ceylon 不是 Java,它是深受 Java 影响的一种新语言,它的设计者是 Java 的坚定支持者。Java 不会很快消亡,没有哪种语言能够取代它。”—Gavin King

既然已经有了 C/C++、Java™、Scala、Ruby、Python、Perl、Erlang、Lua、Scheme 和其他许多语言,我们还要关注以面向业务企业软件开发为重点的新语言吗?在许多情况下不需要,但是我们来研究一下 Red Hat 未来的语言 Ceylon,看看它是否会取得当今最流行的语言那样的地位。

Ceylon 简介

Ceylon 是由 Gavin King 领导的 Red Hat 新项目。King 是 Hibernate 项目(用 Java 编写的持久化解决方案)的创始人。尽管 King 是 Java 技术的支持者(Java 是适合大规模开发的第一批语言之一),但是他注意到 Java 有许多问题,包括泛型等特性的复杂性、设计粗糙且晦涩难懂的 Standard Edition SDK、粗劣的注解语法、不完善的块结构、对 XML 的依赖性等等。

因此,King 提出了一个问题:根据从 Java 语言和 SDK 的优缺点中学到的经验教训,应该设计出一种什么样的语言?他用 Ceylon 回答了这个问题。Ceylon 是一种静态类型语言,它保留了一些最好的 Java 语言特性(在 JVM 上运行),改进了语言的可读性和内置的模块性,还吸收了高阶函数等函数语言特性,此外,Ceylon 还融合了 C 和 Smalltalk 的一些特性。与 Java 语言一样,这种新语言也以业务计算为重点,但是它在其他领域也很灵活、很有用。

一些人把 Ceylon 称为“Java 杀手”(可能是因为对 Java 语言的未来有质疑),但是,Ceylon 实际上也是在 JVM 上运行,所以它是 Java 技术的扩展而不是替代品。使用 JVM 来支持 Ceylon 的执行是一种理想模型,因为这意味着 Ceylon 代码(与 Java 一样)可以很方便地跨目前支持 JVM 的大多数架构进行迁移。


Ceylon 语言特性

很难将当今的大多数语言简单地归为一种类别,它们的编码风格往往是各种各样的。Ceylon 也一样。Ceylon 是一种静态类型语言,这意味着在编译时要执行类型检查;与其相反的 Lisp 等动态类型语言 会在运行时执行类型检查。与 Java 语言一样,Ceylon 是一种面向对象的语言。它还支持使用典型的 C 语法风格的高阶函数(这意味着这些函数可以采用函数作为输入或输出)。在 Java 语言中,不直接支持高阶函数,所以这个功能是这两种语言之间的重大差异。

但是,有时候语言的改进更多地体现在它取消了什么内容,而不是增加了什么。Ceylon 简化和取消了 Java 语言的一些元素,代之以更简单的方案。简化的例子之一是取消了 publicprotectedprivate 关键字。Ceylon 仅包含括 shared 注解,该注释定义了类的哪些元素是外部可见的。Ceylon 还取消了重载功能,但是提供了此功能的使用更简单语法的替代方法(比如默认和顺序的参数)。

Ceylon 支持继承、序列(数组或列表构造)、泛型、命名参数等等。它包含用于运行时类型管理的特性(在下一节中将研究它的一个示例)。这种语言还在开发过程中,所以最终的特性集可能有变动。


Ceylon 说明

尽管到撰写本文时还没有一个公开可用的 Ceylon 编译器,但是 Ceylon 语言的结构已经确定了,所以可以通过开发示例应用程序来研究和推断它的用法和可读性。本节将研究一些用 Ceylon 编写的示例应用程序,以此说明它的结构。

Hello World

我使用 "Hello World" 程序演示如何创建简单的程序,将一个简单的文本字符串发送到显示器。清单 1 中的示例给出一个名为 hello 的顶级方法,它使用 writeLine 方法将字符串发送到标准输出。

清单 1. 用 Ceylon 编写的 Hello World 程序
doc "Hello World Program"
by "Gavin King"
void hello() {
  writeLine( "Hello World." );
}

还要注意用于 API 文档的注解(与 doxygen 等工具相似),可以通过这些注释指定方法和作者(分别使用 docby 注解)。

Ceylon 类型

Ceylon 包含一组传统的类型,它们作为普通的类实现。这些类型是:

  • Natural无符号整数,包括零
  • Integer有符号整数
  • Float浮点数
  • Whole任意精度的有符号整数
  • Decimal任意精度和任意规模的小数

在默认情况下,NaturalIntegerFloat 类型是 64 位的,但是可以通过给它们加上 small 注解来指定 32 位精度。

Ceylon 类

因为 Ceylon 是面向对象的语言,所以可以使用类的概念来编写代码。 是 Ceylon 中的一个类型,它封装了初始化类的某个对象时如何初始化状态的定义,还封装了一组操作(称为方法)和状态,(类初始值设定项 与该构造函数相似)。

提供一个简单的类有助于您了解 Ceylon 的方法。清单 2 提供了用于计数器类的一个简单的类。第 2 行用一个可选值来定义类,这意味着用户可以提供该类,也可以不提供,这用 Type? 方法来表示。类的主体包含类初始设定项,而不是构造函数。这段代码定义私有变量(除非注释为 shared 的,否则所有元素都是不可见的),然后定义初始化逻辑。首先检查 start 变量是否存在。如果存在,则使用它作为初始计数值。第一个方法被注解为 shared,因此可以在这个类以外的地方看到它,它定义了递增操作。调用这个方法时,它会递增计数器的计数。

最后,定义 getter 方法(把当前的计数器值返回给调用者)和 setter 方法(用调用者提供的值设置当前的计数器值)。注意,这里使用 assign 关键字创建一个变量属性,用它设置计数器值。除了处理构造函数的方式不同(代码嵌套在类中)之外,没有析构函数,也无法实现多个构造函数(这是与 Java 语言的差异之一)。

清单 2. 用 Ceylon 编写的简单类
01    doc "Simple Counting Class"
02    class Counter( Natural? start ) {
03    
04      doc "Class Initializer"
05      variable Natural count := 0;
06      if (exists start) {
07        count := start;
09      }
10    
11      doc "The incrementer"
12      shared void increment() {
13        count++;
14      }
15    
16      doc "The getter"
17      shared Natural currentValue {
18        return count;
19      }
20
21      doc "The setter"
22      shared assign currentValue {
23        count := currentValue;
24      }
25
26    }

既然定义了简单的类,我们来看看如何在 Ceylon 中使用这个类。清单 3 中的代码块使用了 Counter 类。首先要实例化这个类来获得 cnt 对象。注意,在 Ceylon 中没有 new 关键字。在定义了新的 Counter 对象之后,请调用 increment 方法,然后使用 getter 方法获得 Counter 值。注意,在 Ceylon 中 =:= 操作符是不同的:= 只用于指定不可变的值,而用 := 操作符则可以执行变量赋值。

清单 3. 使用 Counter 类
01    Counter cnt = Counter(1);
02    cnt.increment();
03    writeLine( c.currentValue );

Ceylon 鼓励尽可能使用不可变的属性。这意味着用一个值初始化对象,以后不再重新赋值。要想指定某个指定值是可变的 (在初始化后可以修改),必须添加注释 variable,参见 清单 2 中的第 5 行。

最后要研究的是 Ceylon 控制结构中的一个关键差异。注意,在许多语言中,可以省略条件表达式后的花括号 ({}),比如下面所示的 statement 语句:

if (cnt > 10) statement();

Ceylon 不允许使用这种语法,要求必须包含花括号。这意味着上面的示例代码在 Ceylon 中必须写成:

if (cnt > 100) { statement(); }

因为省略花括号是 C 中最常见的错误之一,所以强制使用这种正确的编码样式的做法很受人们欢迎。

高阶函数

Ceylon 包含称为一阶函数 的函数式编码样式。这意味着将函数用作高级对象,还可以用作函数的参数,从函数中返回。以 King 文章中的 repeat 方法定义为例(参见清单 4)。在这种情况下,它有两个参数:一个 Natural(表示要重复的次数)和一个方法参数(表示要调用的函数)。在 repeat 方法主体内,只需创建一个 for 循环(使用范围操作)并调用作为方法参数来传递的函数即可。

清单 4. Ceylon 中的高阶函数
01    void repeat( Natural times, void hfunction() ) {
02      for (Natural n in 1..times) {
03        hfunction();
04      }
05    }

使用这个方法很简单,参见清单 5 的第 7 行。如下所示,所使用方法的名称中没有参数。

清单 5. 在 Ceylon 中使用高阶函数
01    void sayhello() {
02      writeLine( "Hello World." );
03    }
04
05    ...
06
07      repeat( 10, sayhello );

与支持函数编程的其他语言不同,Ceylon 不支持匿名函数 (直接出现在表达式中的未命名函数)。它支持闭包(实质上是可以在另一个函数中引用状态的函数)。

类型收缩

Ceylon 不包含 Java 语言中的 instanceof 操作符;也不包含 C 中的类型转换。相反,Ceylon 实现所谓的类型收缩 (type narrowing),使用它在一个步骤中检查并减少某个对象的引用类型。请考虑清单 6 中的代码片段。该代码使用特殊的 (is ... ) 构造检查某个对象引用是否是给定的类型。确定类型之后,则会使用与该类型有关联的方法。这个构造与 清单 2 中用来处理可选参数的 (exists ...) 构造相似。

清单 6. Ceylon 中的类型收缩
01    Object obj = <some object>;
02    
03    switch (obj)
04    
05      case (is Counter) {
06        obj.increment();
07      }
08      case (is ComplexCounter) {
09        obj.incrementBy(1);
10      }
11      else {
12        stream.writeLine("Unknown object");
13      }

Ceylon 包含另一个相似的句法 (nonempty ...),可以对序列(数组或列表)应用它,判断序列是否不包含元素,因此不能应用序列操作。

最后注意,Ceylon 中 switch 语句的语法与 C 和 Java 语言不同。在这两种语言容易出错的地方,Ceylon 要求所有格有严格的块结构,取消了 default 所有格,保留了 else 块。Ceylon 还确认(在编译时)switch 语句包含详尽的实例测试列表,至少包含 else 子句,从而提供完整的覆盖范围。编译器自动地检查这些 switch 语句,如果没有覆盖某个实例,会产生错误。

其他控制结构

Ceylon 实现传统的 if...else 语句,还实现 Java 语言的异常处理特性(trycatchfinally)。Ceylon 还创建了 fail 块,在 for 循环中使用它处理循环提前中断的情况。请考虑清单 7 所示的示例。

清单 7. 说明 Ceylon 的 fail 块
01    for (Instrument i in instruments) {
02      if (i.failing()) {
03        break;
04      }
05    }
06    fail {
07      // Take some action...
08    }

这是 C 和 Java 语言中常见的设计模式,因此在 Ceylon 中增加它是很有用的。


Ceylon 的未来

正如 King 指出的,Ceylon 是一个社区项目,需要软件工程师和测试人员帮助设计、构建和检验这种语言和 SDK。这个号召会鼓励 Java 语言用户提出反馈,帮助支持他们从 Java 迁移到 Ceylon。King 仍然没有明确说明 Ceylon 的现状,只是说明语言规范和 ANTLR (Another Tool for Language Recognition) 句法已经存在了。


展望未来

尽管一些人可能会质疑新语言的必要性,但是应该把语言看作可以用来解决问题的工具集。并非每种语言都适合解决任何问题,但是某些语言非常适合特定的解决方案领域;因此,可以使用多种语言是好事。因为 Ceylon 仍然在开发过程中,还不确定它是否会成为流行的语言。但是,这种语言提供很多让人感兴趣的特性,当最终确定该语言中包含的特性时,有必要深入研究一下这些特性。

参考资料

学习

获得产品和技术

讨论

  • 加入 developerWorks 中文社区,developerWorks 社区是一个面向全球 IT 专业人员,可以提供博客、书签、wiki、群组、联系、共享和协作等社区功能的专业社交网络社区。

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux, Open source
ArticleID=741797
ArticleTitle=Ceylon:真正的进步抑或只是另一种语言?
publish-date=07202011