Ceylon语言介绍第一部分(翻译)——Hibernate之父的又一力作

原文:http://in.relation.to/Bloggers/IntroductionToCeylonPart1

这是Ceylon语言系列文章的第一部分。要注意的是语言的特性可能在最终版发布之前发生改变。

关于Ceylon

Ceylon是一门新的语言,它运行在Java虚拟机上,目前正有我所在的小组开发,它隶属于RedHat。我们都是Java和Java生态系统的粉丝,因为它的实用性、广阔的文化氛围和开发社区、天生适用于商业应用以及可移植性。然而我们必须承认这门语言和其现有的类库,已经过了15年的发展,它不能再提供更好的功能来解决现在的商业问题。
  • Ceylon的设计目标包括:
  • Java和C#开发者可以很容易的学习和掌握。
  • 消除了一下Java的啰嗦语法,使其容易阅读。
  • 更加类型安全。
  • 提供一个声明式的语法来表达层级信息,比如定义用户接口、结构化数据以及系统配置,这导致了Java平台过度的依赖于XML。
  • 支持不变对象和高级函数(功能)
  • 极好的元数据编程支持,这使得编写框架变得非常容易
  • 提供内置模块解决方案
最重要的是,Ceylon的设计目的是让大型团队更好的协作
Ceylon编译器还没有完成,所以你还不能使用Ceylon编写代码。不管怎样,我愿意让社区参与语言和SDK的开发,所以这个系列文章是给对Ceylon感兴趣的人一个提前预览。
让我们从头开始吧。

编写一个简单的程序

这是一个经典的例子程序。
void hello() { 
    writeLine(
"Hello, World!");
}

这个方法在控制台打印出“Hello, World!”。这是一个顶层方法就像C语言函数--它直属于包含它的包中,它不是一个任何类型的成员。你不需要接收一个对象来调用顶层方法,你只要像下面这样就可以调用它:
hello();

Ceylon没有Java风格的静态方法,但是你可以使用顶层方法来充当同样的角色。静态方法存在的问题是它打乱了程序的块结构。Ceylon拥有严格的块结构--一个内嵌的块总是可以在所有包含它的块中被访问。这与Java的静态方法不同。
这个方法使用了void关键字,这表示方法没有返回值。当方法被执行时,它调用另一个顶层方法writeLine(),这个方法在控制台中显示它的参数。

连同void关键字,还有一个命名为Void的类型,其再任何void方法中被返回,这也是Ceylon类型系统的根类型。
doc "The root type, supertype of
      both Object (definite values) 
      and Nothing (the 
null value)."
see (Nothing, Object)
shared 
abstract class Void() {}

可能对void方法有一个返回类型很不解。对此的解释就是Ceylon内所有的方法都是函数。(但未必都是函数--比如hello(),一个Ceylon函数能够有边缘效应。)

在一个非常抽象层里,每个方法都接受参数并有返回结果。对于Void类型,简单来说就是提供表示未知值和未知类型的一种途径。你可以给Void分配任何值,包括null,但是它无法被再次回收,即使知道它的类型值是什么。因此理论上void方法有返回值,只是我们无法知道关于它值的任何信息。现在这听起来可能没什么用处,但是当我们讨论first-class函数和Ceylon类型安全的元数据模型时将证明其非常有用。

添加内嵌的文档

通常给像hello()这样重要的方法上添加注释文档是一个好习惯。一个方式就是使用C语言风格的注释,就像下面这样:
/* The classic Hello World program */ 
void hello() {
    writeLine(
"Hello, World!");
}

或者像这样:
//The classic Hello World program 
void hello() {
    writeLine(
"Hello, World!");
}

但是更好的方式是使用doc注解来写注释。
doc "The classic Hello World program" 
void hello() {
    writeLine(
"Hello, World!");
}

doc注解包含的文档被包含在Ceylon文档编译器输出中。文档编译器还将支持其它几个注解,包括by,用来指定程序作者;see,用来关联其它代码元素;以及throws,报告用户程序执行抛出的异常类型。
doc "The classic Hello World program" 
by 
"Gavin" 
see (goodbye) 
throws (IOException)
void hello() { 
    writeLine(
"Hello, World!");
}

同样还有一个deprecated注解,用来说明程序元素在将来的版本中会被移除。
注意,当一个注解的参数是字面原文形式,那么久不需要有关闭括号。
像doc,by,see和deprecated这类的注解不是一个关键字。它们只是普通的标识符。同样的对于语言中定义的注解:abstract,variable,shared,formal,actual和friends也都不是关键字。但void是关键字。

字符串和字符串内插

Hello World程序--现在广泛流行--提供非常有限的用户体验。一个更典型的例子在不同的运行时产生不同的输出。

让我们来询问我们的程序,以便它告诉我们更多关于它自己的信息。
doc "The Hello World program 
      version 1.1!"
void hello() { 
    writeLine(
"Hello, this is Ceylon " process.languageVersion
              
" running on Java " process.javaVersion "!");
}

我们能看到Ceylon的字符串提供的两个好处。第一就是可以分割字符串为多行,这对于在doc注解中写文档非常有帮助。第二个就是我们可以在字符串内部插入表达式,从技术上来讲,一个带有表达式的字符串不在是一个真正的字符串了,而被看做一个字符串模板。
一个字符串表达式必须开头和结尾都必须是字符串,下面的语法是错误的:
writeLine("Hello, this is Ceylon " process.languageVersion); //compile error!

在最后加上一个空的字符串就能修正上面例子的错误。
writeLine("Hello, this is Ceylon " process.languageVersion "");

注意,在Ceylon中这不是唯一连接字符串的方法。其实这只是对于在不变的字符串中插入变量或表达式有用。+操作符可作为另外一种选择,还有更多灵活的例子:
writeLine("Hello, this is Ceylon " + process.languageVersion + 
          
" running on Java " + process.javaVersion + "!");

但是不要看到这两种方式的输出是一样的就认为它们是等价的。+操作符仅仅是对表达式求值并产生一个不可变的String对象。而String模板是一个Gettable<String>的表达式,其不马上对内插表达式求值(有点像Hibernate里的懒加载)。如果你打印String模板对象两次,你可能会看到两个不同的输出。其实,String模板是一种closure(闭包)--一个重要的概念,我将在后面介绍。

处理没找到的对象

大多数程序都要求接收输入并产生输出,并且程序依赖于接收的输入。当然,这么做对用户来说有点苛刻,但是,一些额外的工作必须做!

对此,提供一个改良版本的Hello World程序,其从命令行接收一个名字作为输入。我们必须考虑在命令行什么都没输入的情况,这样就能给我们一个机会去体验Ceylon如何处理Null值,这可与Java于C#的处理方式有着很大的不同。
doc "Print a personalized greeting" 
void hello() {
    String
? name = process.arguments.first; 
    String greeting; 
    
if (exists name) {
        greeting 
= "Hello, " name "!";
    }
    
else {
        greeting 
= "Hello, World!"
    }
    writeLine(greeting);
}

process对象有一个arguments属性,它持有命令行参数的Sequence(顺序)。本地变量name被这些参数初始化,参数如果存在的话,本地变量被声明为String类型,否则他可能包含一个null值。if(exists...)控制结构用来初始化本地非空变量greeting,如果name不是null的话就内插到消息字符串中。最终,消息被输出到控制台。
这与Java不一样,本地变量,参数和属性都可以包含null值,但必须明确声明其类型。这与其它语言持有类型安全的null值不同,在Ceylon中可选的类型不是一个封装定值的algebraic数据类型,而是一个ad-hoc union type(联合类型)。语法T|S表示联合T和S。一个可选的类型Noting|X代表任何类型,X是一个定值类型。Ceylon允许我们使用缩写X?代表Noting|X。
doc "The type of null."
shared 
abstract class Nothing() 
        of nothing
        
extends Void() {}

null值关联一个Nothing类型的实例,但是它不是一个Object的实例。因此这是一种简单分配本地变量为Null(不是一个可选类型)的方式。
doc "Represents a null reference."  
object nothing 
extends Nothing() {}

doc 
"Hides the concrete type of nothing."  
shared Nothing 
null = nothing;

Ceylon编译器也不允许你最T类型的值做任何“危险”的事情,在Java里这样会抛出NullPointerException。if(exists...)结构让我们从X?类型提取X类型的值,从而允许我们调用X值的方法。

事实上,没有可能在一个可选类型的表达式里使用==操作符,你不能像在Java中那样使用if(x==null)。这有助于避免像Java中的不良操作==,x==y在Java中如果x和y都是null将返回true.

在if(exists...)条件中可以声明本地变量name:
String greeting; 
if (exists String name = process.arguments.first) {
    greeting 
= "Hello, " name "!";

else {
    greeting 
= "Hello, World!"
}
writeLine(greeting);

自从我们不能再if(exists...)结构外部使用变量name,这个语法在很多时候被首选使用。

默认参数

一个方法参数可以指定一个默认值。
void hello(String name="World") {
    writeLine(
"Hello, " name "!");
}

这样我们就不需要在调用方法时指定参数值。
hello(); //Hello, World!
hello("JBoss"); //Hello, JBoss!

默认参数必须在所有必须参数列表的最后面。
Ceylon同样支持参数序列,使用T...语法。我们将在for循环序列中讲述。

还有更多。。。

在第二部分,我们将看到如何定义一个自身类型:classes,interfaces和objects.

posted on 2011-05-24 07:25 kuuyee 阅读(2850) 评论(1)  编辑  收藏 所属分类: JEERuby/Python/Ceylon

评论

# re: Ceylon语言介绍第一部分(翻译)——Hibernate之父的又一力作[未登录] 2011-10-20 02:39 1

游戏支付平台www.hwd518.com  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

导航

<2011年5月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

统计

随笔分类(139)

Linux内核

搜索

积分与排名

最新评论

阅读排行榜