Blog of Stéphane Épardaud

Ceylon 1.2.1 is now available

Three months after the last major release, Ceylon 1.2.1 is a new maintenance release, with almost 100 issues closed, including new features, improvements and bug fixes such as:

  • you can now iterate java.lang.Iterable values in for statements and use java.lang.AutoCloseable values in try statements,
  • support for Java 9 and Jigsaw modules,
  • experimental support for type functions on the JVM,
  • reduced run-time dependencies for your Ceylon program,
  • better interoperation with JavaScript arrays,
  • better compatibility with previous and future Ceylon releases.

Note that for the JVM backend, this release is backwards-compatible with the previous major release (1.2.0), which means you can use modules compiled with 1.2.0 on a 1.2.1 distribution out of the box. This is not as easy the other way around, if you want to run modules compiled for 1.2.1 on a 1.2.0 distribution, which is why we recommend you upgrade to 1.2.1.

Sadly, on the JavaScript backend, we had to break binary compatibility to fix serious interoperation issues, and so modules compiled for 1.2.1 and 1.2.0 are not compatible. We recommend you upgrade your distribution to 1.2.1 and recompile your modules.

About Ceylon

Ceylon is a modern, modular, statically typed programming language for the Java and JavaScript virtual machines. The language features a flexible and very readable syntax, a unique and uncommonly elegant static type system, a powerful module architecture, and excellent tooling, including an awesome Eclipse-based IDE.

Ceylon enables the development of cross-platform modules that execute portably in both virtual machine environments. Alternatively, a Ceylon module may target one or the other platform, in which case it may interoperate with native code written for that platform.

In the box

This release includes:

  • a complete language specification that defines the syntax and semantics of Ceylon in language accessible to the professional developer,
  • a command line toolset including compilers for Java and JavaScript, a documentation compiler, a test runner, a WAR archive packager, and support for executing modular programs on the JVM and Node.js,
  • a powerful module architecture for code organization, dependency management, and module isolation at runtime,
  • the language module, our minimal, cross-platform foundation of the Ceylon SDK, and
  • a full-featured Eclipse-based integrated development environment.

Language

Ceylon is a highly understandable object-oriented language with static typing. The language features:

  • an emphasis upon readability and a strong bias toward omission or elimination of potentially-harmful or potentially-ambiguous constructs and toward highly disciplined use of static types,
  • an extremely powerful and uncommonly elegant type system combining subtype and parametric polymorphism with:
    • first-class union and intersection types,
    • both declaration-site and use-site variance, and
    • the use of principal types for local type inference and flow-sensitive typing,
  • a unique treatment of function and tuple types, enabling powerful abstractions, along with the most elegant approach to null of any modern language,
  • first-class constructs for defining modules and dependencies between modules,
  • a very flexible syntax including comprehensions and support for expressing tree-like structures,
  • fully-reified generic types, on both the JVM and JavaScript virtual machines, and a unique typesafe metamodel.

More information about these language features may be found in the feature list and quick introduction.

IDE

Ceylon IDE now features the following improvements, along with many bugfixes and a number of performance enhancements:

  • improved documentation hover,
  • better UI responsiveness,
  • support running on Java 9.

A number of important subsystems have been abstracted and rewritten in Ceylon, to support the ongoing development of the new IntelliJ-based IDE for Ceylon.

SDK

The platform modules, recompiled for 1.2.1, are available in the shared community repository, Ceylon Herd.

This release introduces several new platform modules:

  • ceylon.numeric is a cross-platform module containing math operations for Integer and Float. In time it will replace parts of the JVM-only ceylon.math module.
  • ceylon.decimal is a JVM-only module (but soon to be cross-platform) containing arbitrary-length decimal support. In time it will replace parts of the JVM-only ceylon.math module.
  • ceylon.whole is a cross-platform module containing arbitrary-length integer support. In time it will replace parts of the JVM-only ceylon.math module.
  • ceylon.random is a cross-platform module containing random number generators. In time it will replace parts of the JVM-only ceylon.math module.
  • ceylon.interop.browser contains JavaScript-only interoperation functions and types for the DOM, HTML and XMLHttpRequest.

Along with several API enhancements and bugfixes, including:

  • Many new features for ceylon.test, the Ceylon Test Suite.
  • Performance improvement of the ceylon.json parser.

Web IDE

You can try Ceylon using the Web IDE, featuring syntax highlighting, interactive error reporting, autocompletion, online documentation, and persistence and code sharing via Gist.

The Web IDE serves a dual purpose as a standard example demonstrating the use of Ceylon for web application development and deployment to the OpenShift cloud platform.

Community

The Ceylon community site, http://ceylon-lang.org, includes documentation, and information about getting involved.

Source code

The source code for Ceylon, its specification, and its website, is freely available from GitHub.

Information about Ceylon's open source licenses is available here.

Issues

Bugs and suggestions may be reported in GitHub's issue tracker.

Migrating from Ceylon 1.2.0

Migration from Ceylon 1.2.0 is easy. To recompile a module for 1.2.1:

  • First ensure that its dependencies have also been recompiled.
  • If it imports a Ceylon SDK platform module, upgrade the version number specified by the module import statement from "1.2.0" to "1.2.1" .
  • If it was compiled against Ceylon 1.2.0 you should still be able to use it in 1.2.1 for the JVM backend, as it is backwards-compatible. Sadly, this is not the case for the JavaScript backend, and so you will need to recompile your modules with 1.2.1.

Acknowledgement

As always, we're deeply grateful to the community volunteers who contributed a substantial part of the current Ceylon codebase, working in their own spare time. The following people have contributed to Ceylon:

Gavin King, Stéphane Épardaud, Tako Schotanus, Tom Bentley, David Festal, Enrique Zamudio, Bastien Jansen, Emmanuel Bernard, Aleš Justin, Tomáš Hradec, James Cobb, Ross Tate, Max Rydahl Andersen, Mladen Turk, Lucas Werkmeister, Roland Tepp, Diego Coronel, Matej Lazar, John Vasileff, Toby Crawley, Julien Viet, Loic Rouchon, Stephane Gallès, Ivo Kasiuk, Corbin Uselton, Paco Soberón, Michael Musgrove, Daniel Rochetti, Henning Burdack, Luke deGruchy, Rohit Mohan, Griffin DeJohn, Casey Dahlin, Alexander Altman, Alexander Zolotko, Alex Szczuczko, Andrés G. Aragoneses, Anh Nhan Nguyen, Brice Dutheil, Carlos Augusto Mar, Charles Gould, Chris Gregory, klinger, Martin Voelkle, Mr. Arkansas, Paŭlo Ebermann, Vorlent, Akber Choudhry, Renato Athaydes, Flavio Oliveri, Michael Brackx, Brent Douglas, Lukas Eder, Markus Rydh, Julien Ponge, Pete Muir, Nicolas Leroux, Brett Cannon, Geoffrey De Smet, Guillaume Lours, Gunnar Morling, Jeff Parsons, Jesse Sightler, Oleg Kulikov, Raimund Klein, Sergej Koščejev, Chris Marshall, Simon Thum, Maia Kozheva, Shelby, Aslak Knutsen, Fabien Meurisse, Sjur Bakka, Xavier Coulon, Ari Kast, Dan Allen, Deniz Türkoglu, F. Meurisse, Jean-Charles Roger, Johannes Lehmann, allentc, Nikolay Tsankov, Chris Horne, Gabriel Mirea, Georg Ragaller, Harald Wellmann, klinger, Oliver Gondža, Stephen Crawley, Byron Clark, Francisco Reverbel, Jonas Berlin, Luke Hutchison, Nikita Ostroumov, Santiago Rodriguez, Sean Flanigan.

Ceylon on Java 9 + Jigsaw

Everyone is talking about modules these days. New languages try to incorporate them, and older languages try to retrofit them in. Which is great news, because modules are essential. Java 9 is around the corner, because it's supposed to come out next year, and the really big new feature is modularity, which it calls the Jigsaw project.

Ceylon is a language that featured modularity from the start, as part of the language and not as an afterthought requiring complex third-party tool integration. In fact, at the time we designed our Java JDK integration (at the time of Java 7), we went as far as using the Jigsaw modularity plans for the JDK (yes Jigsaw got delayed a few times) from the start, requiring JDK users to import Jigsaw modules as they were planned at the time, rather than import the whole JDK in one go. So perhaps we were the first ones with a modular JDK, in some sense :)

Java 9’s Jigsaw

Jigsaw is a very large project, which includes the following changes:

  • Modularisation of the JDK into smaller units, such as java.base, java.xml that Ceylon users of the JDK are already familiar with.
  • This modularisation means removal of rt.jar that contained every JDK class. In fact it's been replaced by a bootmodules.jimage file which is not a jar, but whose contents can be accessed by a virtual NIO FileSystem at jrt:/.
  • You can write your own modules. To turn your Java code into a Java 9 module, you simply add a module descriptor in a file called module-info.java (much like Ceylon module descriptors, or Java package descriptors), which describes your module and the Java 9 compiler and jar tools will then generate a jar with a module-info.class descriptor at the root of the jar.
  • That module descriptor allows you to specify the module name, the packages it exports, the name of the modules it imports and a few other things. But not versions, unfortunately, which are currently "out of scope" in Java 9.
  • You can run your code as previously from the classpath, or as modules from the module path. The module path is just a folder in which you can place your modules and the JRE will look them up for you based on module name alone.

Ceylon and Jigsaw

Java 9 has two early-access (EA) downloads for users to try the module system. Only one of them includes user modules. Make sure you use that one if you want to try out Ceylon running on Java 9.

Over the past weeks I've worked on getting Ceylon compiling and running on Java 9. This involved (among other details) the following things:

  • Generating module-info.class files from Ceylon module descriptors.
  • Generating module-info.class files for the Ceylon distribution modules which are not written in Ceylon (like the compilers or runtime system).
  • Making use of the Java 9 module descriptors for the shared packages information it contains (something supported by Ceylon since the beginning, but which was lacking for plain Java jars).
  • Backporting Java 9 code that deals with modules to the javac fork we use to compile Java files and generate bytecode.
  • Dealing with the removal of rt.jar and the boot classpath.
  • Creating a new tool ceylon jigsaw which allows for the creation of a Java 9 module path.
  • Making sure we can run Ceylon modules as Java 9 modules as an alternative to the four existing JVM runtimes which are the JBoss Modules, classpath, OSGi or Java EE.
  • Make sure we can build and run on any of Java 7,8,9. This means that by default we do not generate Java 9 module descriptors, because several tools have problems dealing with them at this time.
  • We have split some things out of the ceylon.language module so that it no longer depends on the compilers and type-checker, which means a lighter minimal runtime, which will be even further improved in the next weeks with more dependency removals :)

Just tell me how to try this!

I will spare you the many details of this work, but with help from the Java 9 team, this is how you can run your Ceylon modules on a Java 9 runtime:

  • Download the Java 9 EA with Jigsaw.
  • Get the Ceylon distribution code, and compile it with ant -Djigsaw=true clean dist to get the Java 9 module descriptors.
  • Write your Ceylon module normally, but compile it with .../ceylon/dist/dist/bin/ceylon compile --generate-module-info to generate the Java 9 module descriptors.
  • Create your Java 9 module path in an mlib folder with .../ceylon/dist/dist/bin/ceylon jigsaw create-mlib my.module/1.
  • Run your Ceylon module on Java 9 with .../jdk1.9.0-jigsaw/bin/java -mp mlib -m ceylon.language my.module/1. At the moment, the ceylon.language module acts as main module and does the required setting up of the Ceylon runtime before loading and invoking your Ceylon module.

That's all there is to it!

Caveats

Java 9 is not complete yet, and our support for Java 9 is also not complete. There will be issues and bugs, and in fact we already know of several limitations, such as the following:

  • While you can import a pure Java 9 module from Ceylon, we will respect its exported packages, but we will not respect its dependencies, because Java 9 modules do not include dependency versions. In fact, even the module's version is not stored in the source module descriptor, but added by an optional flag to the Java 9 jar tool. Ceylon requires module dependencies to describe a version, so we have to combine the Java 9 module descriptor with another descriptor such as an OSGi descriptor or a Maven pom.xml descriptor. This merging of information is not currently done.
  • Java 9 does not currently support optional modules or module cycles. It is not clear if they will support them at this time, unfortunately.
  • The ceylon import-jar tool may complain about module visibility artifacts. We intend to fix this in time, but for now you can use --force.
  • The JDK module list we used in Ceylon has slightly changed in Java 9. This is what we get for being the first to support Jigsaw ;) For example, the javax.xml module has been renamed to java.xml. We have set up aliases so that it "just" works, but there are modules that have been merged, and packages that have changed module, so it will not always work.
  • The Java 9 runtime has been tested, but not as thoroughly as the existing JBoss Modules, classpath, OSGi or Java EE runtimes. We expect a few issues in the Ceylon metamodel.

Troll alert

This is a rather unusual blog entry, one I was not thinking we'd ever have to write, but after a long debate, we've decided to go public about certain events that have happened to the Ceylon community.

We are being aggressively harassed by a Troll for a month now, which is taking the following forms:

  • Logging on our Gitter channels, insulting and threatening users, then renaming his GitHub account so we cannot find/ban him.
  • Using fake identities to ask us for help on Gitter for hours on end, only to reveal later he was the troll and resume insults/threats.
  • Impersonating Gitter users to make them look bad.
  • Spreading lies about Ceylon on other JVM languages discussion channels.
  • Using sock puppet accounts on reddit to turn many threads into Ceylon bashing or ad-hominem attacks on Ceylon team members.
  • Defacing the Ceylon Wikipedia page [Edit: it's not clear yet, it could be a honest mistake on both parts].
  • And other things I cannot reveal here.

Since I have no doubt at all our troll is reading this, you will understand I am not revealing all the information that we have on what he's done and who he is. In fact it's a pretty difficult exercise.

I also don't want to explicitly name his identities here because I don't believe in mob justice, I hope you will understand that.

Naturally we've tried many things to make sure he stops poisoning our community, and are still working on measures behind the scenes, but his impact cannot be ignored.

Although we've always tried to follow the usual Troll-avoidance strategy of ignoring him, we have many people in the Ceylon community who see these events and wonder what's going on. They don't understand why every new user is suspect (our troll uses about two new fake accounts per day), or why suddenly a seemingly sane person will start throwing insults at everyone. The more we talk to him, and the more we talk about him, the more persisting he becomes, so we don't want to make it worse.

But there has to be an explanation we can point to when people ask what the hell is happening, so this is it.

We have a toxic person in our community, we haven't been able to get rid of him no matter how many times we asked him, and we don't have the tools to prevent him from harassing us, and he knows it. What goes on in his mind is beyond our ability to understand, but the fact is he exists, and seems driven by some motive to spend hours every day annoying us.

We are, again, withholding information about him and about the various things we are doing behind the scenes to deal with him, but rest assured we are not sitting idle.

That's pretty much as I can say at this point. If you see someone throwing insults at people on our Gitter channel, this is not something we condone at all, and we keep banning his new accounts for that, so don't let our apparent lack of reaction (besides the banning) fool you into thinking that we're silently condoning his attitude. We're not.

Thanks for your understanding.

Running Ceylon on OpenShift

This year we released three different ways you can run your Ceylon code on OpenShift:

  • Bare-bones, using the Ceylon cartridge,
  • Writing a verticle in Ceylon, using the Vert.x cartridge, or
  • Packaging your Ceylon application as a .war file and running it on the WildFly cartridge.

In this post we will see how you can write and publish a bare-bones application on OpenShift Online using the OpenShift Ceylon cartridge. The Vert.x and WildFly methods will be described in a later blog post.

The OpenShift Ceylon cartridge is for OpenShift V2. Yes I know that's old, as it is now V3, but the online version of OpenShift is still V2, so it's still relevant. We are working on the V3 cartridge too, and it should be out soon.

Writing a bare-bones web application with Ceylon

Let's start by creating a new Ceylon project:

$ ceylon new hello-world ceylon-blog-openshift
Enter module name [com.example.helloworld]: openshift.bare  
Enter module version [1.0.0]: 1
Would you like to generate Eclipse project files? (y/n) [y]: n
Would you like to generate an ant build.xml? (y/n) [y]: n
$ cd ceylon-blog-openshift

Now compile and run it to check that everything is under control:

$ ceylon compile
Note: Created module openshift.bare/1
$ ceylon run openshift.bare/1
Hello, World!

Now let's make it start an HTTP server, by using the ceylon.net module and adapting its documentation code sample.

First import that module in source/openshift/bare/module.ceylon:

native("jvm")
module openshift.bare "1" {
  import ceylon.net "1.2.0";
}

Then use it in source/openshift/bare/run.ceylon:

import ceylon.io { SocketAddress }
import ceylon.net.http.server { ... }

shared void start(String host, Integer port){
    //create a HTTP server
    value server = newServer {
        //an endpoint, on the path /hello
        Endpoint {
            path = startsWith("/");
            //handle requests to this path
            service(Request request, Response response)
                    => response.writeString("hello world");
        }
    };
    //start the server
    server.start(SocketAddress(host, port));
}

shared void run(){
    start("127.0.0.1", 8080);
}

Let's run it:

$ ceylon compile
Note: Created module openshift.bare/1
$ ceylon run openshift.bare/1
Starting on 127.0.0.1:8080
Debug: XNIO version 3.3.0.Final 
Debug: XNIO NIO Implementation Version 3.3.0.Final 
Httpd started.

And try it locally at http://localhost:8080, it should show a web page with hello world.

Adapt our application for running on OpenShift

Now let's adapt it to run on OpenShift, where the host name and port are specified by OpenShift, by using the ceylon.openshift module to see if we are running on OpenShift and if yes, bind to the right address.

First import the OpenShift module in source/openshift/bare/module.ceylon:

native("jvm")
module openshift.bare "1" {
  import ceylon.net "1.2.0";
  import ceylon.openshift "1.2.0";
}

And use it in in source/openshift/bare/run.ceylon:

import ceylon.openshift { openshift }
import ceylon.io { SocketAddress }
import ceylon.net.http.server { ... }

shared void start(String host, Integer port){
    //create a HTTP server
    value server = newServer {
        //an endpoint, on the path /hello
        Endpoint {
            path = startsWith("/");
            //handle requests to this path
            service(Request request, Response response)
                    => response.writeString("hello world");
        }
    };
    //start the server
    server.start(SocketAddress(host, port));
}

shared void run(){
    if(openshift.running){
        start(openshift.ceylon.ip, openshift.ceylon.port);
    }else{
        start("127.0.0.1", 8080);
    }
}

So now it can run either locally as before, or in OpenShift.

Configuring our application for the OpenShift Ceylon cartridge

Let's create the required OpenShift structure to tell the OpenShift Ceylon cartridge how to run our module. We do this by installing the OpenShift Ceylon command-line plugin:

$ ceylon plugin install ceylon.openshift/1.2.0
Scripts for ceylon.openshift installed in /home/stephane/.ceylon/bin/ceylon.openshift

And now we run it:

$ ceylon openshift init openshift.bare/1
Installing file .openshift/config/ceylon.properties: Generated
...

For those who want more information, or tune how the application is deployed by the OpenShift Ceylon cartridge, the documentation has a lot more information.

Our application is now ready to be run on OpenShift.

Deploying our application to OpenShift Online

Now, assuming you already have an OpenShift Online account, and the rhc command installed, you can proceed to create an OpenShift application with the Ceylon cartridge:

$ rhc create-app --no-git -a test https://raw.github.com/ceylon/openshift-cartridge/master/metadata/manifest.yml
The cartridge 'https://raw.github.com/ceylon/openshift-cartridge/master/metadata/manifest.yml' will be downloaded and installed

Application Options
-------------------
Domain:     fromage
Cartridges: https://raw.github.com/ceylon/openshift-cartridge/master/metadata/manifest.yml
Gear Size:  default
Scaling:    no

Creating application 'test' ... done


Waiting for your DNS name to be available ... done

Your application 'test' is now available.

  URL:        http://test-fromage.rhcloud.com/
  SSH to:     ...@test-fromage.rhcloud.com
  Git remote: ssh://...@test-fromage.rhcloud.com/~/git/test.git/

Run 'rhc show-app test' for more details about your app.

This created our application on OpenShift Online, and gave us a URL at which we can access it (http://test-fromage.rhcloud.com/), as well as a Git repository where we can push our application (ssh://...@test-fromage.rhcloud.com/~/git/test.git/).

Now we just have to turn our application into a Git repository and add the openshift remote Url that rhc gave us just above:

$ git init
Initialised empty Git repository in /home/stephane/src/java-eclipse/ceylon-blog-openshift/.git/
$ git remote add openshift ssh://...@test-fromage.rhcloud.com/~/git/test.git/

The Ceylon OpenShift cartridge includes a demo sample app that we can get rid of by forcing a push of our current application to OpenShift:

$ git add source .openshift
$ git commit -m "Initial commit"
...
$ git push -f openshift master
Counting objects: 23, done.
Delta compression using up to 16 threads.
Compressing objects: 100% (18/18), done.
Writing objects: 100% (23/23), 3.79 KiB | 0 bytes/s, done.
Total 23 (delta 1), reused 0 (delta 0)
remote: Stopping Ceylon cart
remote: Application is already stopped
remote: Repairing links for 1 deployments
remote: Building git ref 'master', commit 58ab35c
remote: 
remote: Building Ceylon app...
remote: Compiling every module in /var/lib/openshift/../app-root/runtime/repo//source for the JVM:
remote: Note: Created module openshift.bare/1
remote: Ceylon build done.
remote: Preparing build for deployment
remote: Deployment id is ...
remote: Activating deployment
remote: TODO
remote: Starting Ceylon cart
remote: Executing /var/lib/openshift/.../ceylon/usr/ceylon-1.2.0/bin/ceylon
remote: With params: run   --rep=/var/lib/openshift/.../app-root/runtime/repo/.openshift/config/modules --cacherep=/var/lib/openshift/.../app-root/runtime/repo//cache --rep=https://modules.ceylon-lang.org/repo/1/ --rep=/var/lib/openshift/.../app-root/runtime/repo//modules openshift.bare/1 
remote: With JAVA_OPTS:  -Dcom.redhat.ceylon.common.tool.terminal.width=9999 -Dceylon.cache.repo=/var/lib/openshift/.../app-root/runtime/repo//cache
remote: Ceylon started with pid: 350715
remote: Waiting for http server to boot on 127.5.184.1:8080 ... (1/30)
remote: Waiting for http server to boot on 127.5.184.1:8080 ... (2/30)
remote: Waiting for http server to boot on 127.5.184.1:8080 ... (3/30)
remote: Waiting for http server to boot on 127.5.184.1:8080 ... (4/30)
remote: Found 127.5.184.1:8080 listening port
remote: 
remote: -------------------------
remote: Git Post-Receive Result: success
remote: Activation status: success
remote: Deployment completed with status: success
To ssh://...@test-fromage.rhcloud.com/~/git/test.git/
   2a29bdf..58ab35c  master -> master

That's it, you can now go and check your application online at http://test-fromage.rhcloud.com/.

Congratulations!

Now you can also publish your code online, at GitHub or elsewhere, and every time you push your modifications to the openshift remote, your application will be restarted with your changes.

Stay tuned for the Vert.x and WildFly Ceylon OpenShift deployment guides on this blog.

UK JUG tour

Tom and Stef are going to tour the UK Java User Groups to talk about Ceylon this week, starting with London today, Manchester tomorrow, then Newcastle and Belfast.

Do not miss this if you’re in the UK, check out the details for each date and how to register.