Java希望拥有的十大Ceylon语言功能

发布于:2021-02-12 00:00:07

0

259

0

Ceylon Java javascript

Java 8很好地窃取了Scala的想法,但是这里列出了Java开发人员仍然梦寐以求的Ceylon编程功能。

当Hibernate完成并且功能完善并且需要新的挑战时,该怎么办?对。人们创建了一种新的JVM语言,称为Ceylon。

2013年11月12日,Ceylon 1.0.0终于发布了,我们祝贺Red Hat的整个团队在看起来非常有希望的新JVM语言方面所取得的成就。Ceylon与Scala的竞争将是一个小挑战,但有许多非常有趣的功能使它与众不同。

无论如何,足够多的人是谁。这是我希望在Java中获得的个人十大Ceylon语言功能列表:

1.模块

在Java中,Jigsaw已被推迟了约34次,而我们现在才关闭Java 8 GA!是的,我们有OSGi和Maven,它们在运行时(OSGi)或编译时(Maven)的依赖关系管理方面都工作得很好。但是,使用Apache Felix比较这个黑魔法Maven / OSGi配置…

<plugin>   <groupId>org.apache.felix</groupId>   <artifactId>maven-bundle-plugin</artifactId>   <version>2.1.0</version>   <extensions>true</extensions>   <executions>     <execution>       <id>bundle-manifest</id>       <phase>process-classes</phase>       <goals>         <goal>manifest</goal>       </goals>     </execution>   </executions>   <configuration>     <supportedProjectTypes>       <supportedProjectType>         jar       </supportedProjectType>     </supportedProjectTypes>     <instructions>       <Bundle-SymbolicName>         org.jooq       </Bundle-SymbolicName>       <Export-Package>*</Export-Package>       <Import-Package>         javax.persistence;resolution:=optional,         org.apache.log4j;resolution:=optional,         *       </Import-Package>       <_versionpolicy>         [$(version;==;$(@)),$(version;+;$(@)))       </_versionpolicy>     </instructions>   </configuration> </plugin>

最后,可以在jar级别上控制事物,包括程序包的可见性。仅用几行代码。Java,请集成Ceylon的强大模块支持。

值得一提的是Fantom是另一种具有集成模块支持的语言。参见JodaTime在2011年Devoxx上的Stephen Colebourne的演讲:   “ Scala的Fantom光年还远吗?” 。Stephen还为我们带来了ElSql,这是一种用于Java模板的新外部SQL DSL。

2.序列

这是我第一次看到这种对类型安全的语言的序列的一流支持。Ceylon不仅附带各种收集文字,而且还知道这些构造的类型。具体来说,您可以这样声明一个Iterable:

<code class="java plain">{String+} words = { "hello", "world" };</code>

注意文字的符号。类型 {String+}为,表示它至少包含一个元素。该类型与兼容 {String*},表示可能是空序列。很有意思。

通过这样支持数组文字来继续:

String[] operators = [ "+", "-", "*", "/" ]; String? plus = operators[0]; String[] multiplicative = operators[2..3];

…或元组文字:

<code class="java plain">[Float,Float,String] point = [0.0, 0.0, "origin"];</code>

还要注意范围文字2..3,它允许从原始数组中提取子数组。Ceylon有如此多的序列优势!

还要注意中的问号String?,这是Ceylon声明…的方式。

3.可空类型

Scala知道Option类型,Haskell知道Maybe类型,而 Java 8试图通过添加新的,不可执行的Optional类型进行竞争,但是Ceylon拥有一个非常简单的概念,即可以为空的东西。如果类型后面有问号,则它可以为空。否则,它不为null。总是这样。

为了将可为空的类型转换为不可为空的类型,您必须显式检查:

void hello() {     String? name = process.arguments.first;     String greeting;     if (exists name) {         greeting = "Hello, ``name``!";     }     else {         greeting = "Hello, World!";     }     print(greeting); }

注意exists操作员。它定义了一个新的范围,在该范围内,该name变量已知不为null,即,将其从提升String?为 String。卢卡斯·里兹(Lukas Rytz)认为,这种局部作用域类型的提升通常称为流敏感类型化,这已经在Whiley语言中被观察到。

如果省略该exists检查,则在该字符串插值处将出现编译错误。还有其他有用的结构可以执行临时类型转换:

<code class="java plain">String greeting = "Hello, " + (name else "World"); </code>

该else子句的行为类似于SQL COALESCE()函数,甚至可以链接起来。阅读有关Ceylon的可为善的更多信息  。

4.默认参数

OMG,我希望我们能用Java做到这一点。我们认为,每次我们重载方法时,为什么不仅仅支持默认参数,例如PL / SQL?

void hello(String name="World") {     print("Hello, ``name``!"); }

我无法想到为什么语言不会具有PL / SQL之类的命名和默认参数的一个很好的理由:

-- One of the parameters is optional CREATE PROCEDURE MY_PROCEDURE (   P1 IN NUMBER,   P2 IN VARCHAR2 := 'ABC',   P3 IN VARCHAR2 );    -- Calling the procedure MY_PROCEDURE(   P1 => 1,   P3 => 'XYZ'

因此,这是在大多数情况下避免方法重载的一种方法。当我们要处理替代的,不兼容的类型时,方法重载仍然很繁琐。但是Ceylon不知道,但是在Ceylon……

5.联合类型

好的,这有点深奥。Ceylon的创建者真的很想摆脱方法重载,部分原因是Ceylon也可以编译为JavaScript,而JavaScript不知道函数重载。实际上,根本无法在Ceylon中重载方法。但是,为了能够与Java进行互操作,需要引入联合类型。联合类型 String|Integer可以是String或Integer。那里有方法重载!

void printType(String|Integer|Float val) { ... }     printType("hello"); printType(69); printType(-1.0);

为了“解开”联合类型,您可以val通过执行类似于Java的类型检查来再次利用流敏感类型的 参数instanceof

void printType(String|Integer|Float val) {     switch (val)     case (is String) { print("String: ``val``"); }     case (is Integer) { print("Integer: ``val``"); }     case (is Float) { print("Float: ``val``"); } }

例如,在该范围内, val编译器知道该类型 String是。这继续允许疯狂的东西,例如枚举类型,其中一个类型可以同时是一个或另一个东西:

abstract class Point()         of Polar | Cartesian {     // ... }

请注意,这是由多重继承很大的不同,其中这样的Point会都 Polar 和 Cartesian。但这还不是全部。Ceylon也有……

6.交叉点类型

现在,您可能已经猜到了,这与联合类型的确切含义相反,而Java的泛型实际上也支持这种类型。在Java中,您可以编写:

<code class="java keyword">class X> {}</code>

在上面的示例中, X仅接受Serializable 和的 类型参数 Comparable。在Ceylon,这很疯狂,您可以在其中为本地声明的交叉点类型分配值。事实并非如此!在我们的聊天中,Gavin向我指出了这一令人难以置信的语言功能,其中联合/交叉点类型可以与流敏感类型交互以形成以下内容(由于Ceylon 1.2导致):

value x = X(); //x has type X if (something) {     x = Y();     //x has type Y } //x has type X|Y

有道理吧?所以我问他,是否可以再次与该类型相交, Z加文说,是的!可以完成以下操作:

value x = X(); //x has type X if (something) {     x = Y();     //x has type Y } //x has type X|Y if (is Z x) {     //x has type &Z }

之所以这样,是因为类型交集也以非常有趣的方式与泛型交互。在某些情况下, 可以与相同。换句话说,交集(和并集) 与泛型一起分布,就像加法与乘法一样(在对“就像”的非正式理解中)。如果您愿意为此目的研究语言规范,请参见  §3.7.2主体实例化继承。X&X X

现在,联合和相交类型会变得非常讨厌并且难以重用。这就是Ceylon拥有……

7.输入别名

有没有其他编程语言想到过这个很棒的功能?即使您不支持联合和/或交叉点类型,这也是如此有用。考虑一下Java的泛型。随着泛型的出现,人们开始写类似以下内容的东西:

<code class="java plain">Map>> map = // ...</code>

可以说两件事:

  1. 泛型对Java库非常有用

  2. 执行上述操作时,泛型变得非常冗长

这就是类型别名起作用的地方。看看这个例子:

interface People => Set;

这里的要点是,即使某些冗长的类型经常被重用,您也不需要为上述内容创建显式的子类型。换句话说,您不想滥用子类型多态性作为“简化”通用多态性的捷径。将别名视为一个可扩展的宏,该宏可以相互分配兼容。换句话说,您可以编写:

People?      p1 = null; Set? p2 = p1; People?      p3 = p2;

因此,正如“别名”一词所暗示的那样,您并不是在创建新的类型。您只是给复杂类型一个更简单的名称。但是比类型别名更好的是……

8.类型推断

许多其他语言都具有这种功能,Java在一定程度上也是如此,至少就涉及泛型而言。Java 8在允许使用泛型进行类型推断方面又走了一步。但是Java与诸如Scala或Ceylon之类的语言可以使用局部变量相去甚远:

interface Foo {} interface Bar {} object foobar satisfies Foo&Bar {} //inferred type Basic&Foo&Bar value fb = foobar; //inferred type {Basic&Foo&Bar+} value fbs = { foobar, foobar };

因此,此示例显示了许多组合的功能,包括类型约束,序列类型,联合类型。使用如此丰富的类型系统,在value关键字指示您不想(或者您不能)显式声明类型的情况下,支持这种类型的推断非常重要。我真的很想在Java 9中看到这一点!

阅读有关Ceylon出色的类型推断功能的更多信息。

9.申报地点差异

现在,此功能可能很难理解,因为Java的泛型已经非常难以理解。我最近阅读了Ross Tate,Alan Leung和Sorin Lerner的一篇非常有趣的论文,内容涉及通配符给Java泛型带来的挑战:在Java的Type System中驯服通配符。

泛型仍然是一个非常活跃的研究主题,无论是研究人员还是语言设计人员都无法完全同意使用站点的差异(如Java)还是声明位置的差异(如C#,Scala或Ceylon)对于主流程序员而言确实更好。谈论差异的较旧语言是Eiffel 和OCaml。

Microsoft已在C#中引入了声明站点差异。我会引用Wikipedia中的示例,它很容易理解。在C#中,IEnumerator接口具有协变泛型类型参数:

interface IEnumerator {     T Current { get; }     bool MoveNext(); }

这仅意味着以下将起作用:

IEnumerator<Cat> cats = ... IEnumerator<Animal> animals = cats;

这与Java的使用站点差异完全不同,在Java中,上述内容无法编译,但以下内容可以:

Iterator cats = ... Iterator<!-- ? extends Animal --> animals = cats;

声明站点协方差的主要原因是简单的事实,即在使用站点上冗长程度大大降低了。通配符是Java开发人员的主要苦恼,它们引发了许多Stack Overflow问题,因为这是有关本地范围的通配符的问题:

// Given this interface: public interface X {     E get();     E set(E e); }    // This does not compile: public void foo(X<!--?--> x) {     x.set(x.get()); }

在Ceylon语言之旅中可以看到,Ceylon泛型支持声明站点差异,就像C#和Scala一样。有趣的是,由于两种类型的方差支持各有利弊,因此这些事情如何演变,同时 Ross Tate提倡混合站点方差,这对于Java语言而言确实是一个很好的补充!

现在,这有点复杂,所以让我们看一下一个简单却很棒的功能来汇总……

10.功能和方法

斯特凡·埃帕多(StéphaneÉpardaud)概述的主要内容之一是,Ceylon语言是一种非常普通的语言。在考虑Ceylon如何对待函数(和方法,它们是类型成员函数)时,这一点尤其明显 。我可以在任何地方放置函数。考虑以下示例:

Integer f1() => 1; class C() {     shared Integer f2() {         Integer f3() => 2;         return f3();     } }    print(f1()); print(C().f2());

在上面的示例中,

  • f1()是一个包级函数(非常像Java中的“global”静态函数)

  • f2()是C类中的常规方法

  • f3()是f2()方法中的局部函数

有了Java 8对lambda表达式的支持,这些事情会变得更好一些,但是能够以几乎相同的语法在任何地方声明函数不是很棒吗?

结论:与Ceylon一起玩

现在就这样。不久之后,我们可能会发布有关Ceylon更深奥的语言功能的后续文章。无论如何,您都可以在Eclipse中通过一流的IDE支持免费下载这种有趣的JVM语言。您还可以访问Ceylon文档网站,并使他们的网站将Ceylon代码编译为JavaScript以在浏览器中执行。