Team blog

One Big Repository

Over the last year and a half it has happened quite frequently that users on our mailing lists or Gitter channels asked: "What is this OBR you people keep talking about?". It was something that would most often be mentioned when we were frustrated with the current project setup making things more difficult than necessary.

How it all started

To understand what the OBR really is you first need to know how our project was organized all these years. Ceylon started out with nothing but the parser and the code that checks and models our unique typesystem, we call it the "typechecker". When we started working on the compilers new modules got added, first for the Java Virtual Machine, later for JavaScript. Then we added a module that handles downloading and caching of external modules retrieved from the Herd. This went on to the point that we wound up with 9 separate but very interdependent projects.

The problem

Now of course modularization is a good software engineering practise so there was no problem there. The problem was with the way we had created multiple Git repositories for each of the projects. We started noticing that for certain types of cross-module issues we often had to make changes to multiple repositories at a time. And when you do that, let's say you change 6 repositories for a single bug report or for a single new feature, you lose cohesion. The changes are all separate and you lose sight of the fact that they belong together. So if you need to go back in time looking for a specific problem and when it was introduced and by which code commit it suddenly becomes very hard to synchronize all the repositories in such a way that you get a working system. The famous git bisect becomes impossible to use.

It also caused minor problems when managing issues on GitHub because users, not knowing, would often open issues on the wrong project which meant manually copying the issue from one project to another (and sometimes even we didn't know where to put an issue and it would get moved several times).

Looking for a solution

So at a certain moment it became obvious that our project setup was working against us, that its structure made certain operations way too hard. A single repository on the other hand wouldn't have those problems. A single big repository, the only one for the entire distribution. So we started calling it the "One Big Repository", quickly shortened to "OBR".

But there were doubts that a single repository would become too big and unwieldy. And how would we go from 9 repositories to just 1? Are there tools to do that? And what about our GitHub issues?

Instead we first looked at tools like git submodule and git subtree which would allow us to keep our current projects but still treat them as a one. But after researching it for a while we came to the conclusion that although it might work it does make things more complex for the developer. And given the fact that most of us aren't Git experts and sometimes have trouble enough with it as it is we decided that the added complexity would not work in our favor. Besides the problem with the GitHub issues being separate would still remain.

The execution

One Big Repository it would be then, merging all 9 Ceylon distribution repositories into a single one. But how? No ready-made tools seemed to exist, just fragments of scripts and examples of complex Git commands. And for the GitHub issues we could only rely on their remote API.

I will spare you all the nitty gritty details on the many dozens of practise merges we did to get to a point where we were happy enough with the result but finally, last monday on November 16th, we made public the new OBR, the One Big Repository!

How to use it

Setting up a Ceylon environment for development used to be a big hassle. So much in fact that we created some pretty complex build scripts to do that all for you. So fortunately as a contributor you'd never notice, you'd just type ant setup and everything would be done for you.

But now things have become still easier, for you as a potential contributor the only that is needed is:

$ git clone
$ cd ceylon
$ ant clean dist

For a more thorough explanation on how to set up a development environment and how to go from there to submitting your first contribution please visit Contributing to the compiler backend

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 module and adapting its documentation code sample.

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

module openshift.bare "1" {
  import "1.2.0";

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

import { SocketAddress }
import { ... }

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("", 8080);

Let's run it:

$ ceylon compile
Note: Created module openshift.bare/1
$ ceylon run openshift.bare/1
Starting on
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:

module openshift.bare "1" {
  import "1.2.0";
  import ceylon.openshift "1.2.0";

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

import ceylon.openshift { openshift }
import { SocketAddress }
import { ... }

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(openshift.ceylon.ip, openshift.ceylon.port);
        start("", 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/ 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
The cartridge '' will be downloaded and installed

Application Options
Domain:     fromage
Gear Size:  default
Scaling:    no

Creating application 'test' ... done

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

Your application 'test' is now available.

  SSH to:
  Git remote: ssh://

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 (, as well as a Git repository where we can push our application (ssh://

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://

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: 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= --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 ... (1/30)
remote: Waiting for http server to boot on ... (2/30)
remote: Waiting for http server to boot on ... (3/30)
remote: Waiting for http server to boot on ... (4/30)
remote: Found listening port
remote: -------------------------
remote: Git Post-Receive Result: success
remote: Activation status: success
remote: Deployment completed with status: success
To ssh://
   2a29bdf..58ab35c  master -> master

That's it, you can now go and check your application online at


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.

Porting Ceylon IDE to IntelliJ

We've had many questions about developing Ceylon in IntelliJ IDEA, so I thought it would be worth a quick status update.

TL;DR: The screenshots are below.

As you might know, Ceylon already has the most feature rich IDE of any modern language for the JVM, with some features that even the Java IDE for Eclipse doesn't have. But IntelliJ users don't like having to switch to Eclipse when they code Ceylon, so a few months ago we got serious about porting Ceylon IDE to IntelliJ. Bastien Jansen is working on this fulltime, together with David Festal from SERLI.

The approach they're taking is to refactor reusable functionality of Ceylon IDE out into a separate project ceylon-ide-common. Simultaneously they're rewriting the common code in Ceylon (which David reports is really helping simplify and improve the code). Then this "abstracted" code is reused in the ceylon-ide-intellij project—which is also being written in Ceylon—and in ceylon-ide-eclipse. Thus, ceylon-ide-common gives us a common foundation for both IDEs, and enables us to get some really sophisticated functionality into the IntelliJ IDE very quickly.

Even better, once ceylon-ide-common is stabilized, we can reuse it elsewhere, for example, in the Web IDE, or in the new (experimental) plugin for NetBeans. Bastien was able to add autocompletion to the experimental Netbeans plugin in about 2-3 hours.

This also all demonstrates just how well Ceylon's Java interop works in practice. Here we have Java calling Ceylon and Ceylon calling back to Java all over the place!

The IntelliJ plugin isn't really usable just yet, since David is still working on abstraction of the Ceylon IDE incremental builder, but we expect to have a first release in a handful of months.


Ceylon IDE for IntelliJ already features completion:


Including linked mode argument completion:

linked mode

Outline view and hover:

outline     hover

Live error reporting:


And execution:


Much more functionality is coming soon!

Ceylon 1.2.0 is now available

After a full year in development, and with more than 1500 issues closed, Ceylon 1.2.0 brings new language features, including:

  • named constructors,
  • serialization,
  • native declarations,
  • improved flow-sensitive typing,
  • destructuring for tuples and entries
  • let, switch, if, and object expressions, and
  • more powerful annotation constraints.

Furthermore, the typechecker and JavaScript backend now support type functions as an experimental feature.

Also part of this release are enhancements to the tooling, such as:

  • a new debugger for Ceylon, and
  • the Java EE packaging command, ceylon war.

As always, this release incorporates hundreds of other bugfixes and enhancements.

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.


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.

This release introduces the following new language features and improvements:

  • named constructors,
  • support for serialization libraries in the metamodel,
  • the native annotation, which allows the use of platform-dependent code in cross-platform modules
  • improvements to flow-sensitive typing,
  • destructuring for tuples and entries,
  • let, switch, and if expressions,
  • inline object expressions,
  • more powerful annotation constraints,
  • type argument inference for function references,
  • an improved algorithm for type argument inference in invocation expressions,
  • improvements to analysis of disjointness for sequence types,
  • new type abbreviations, T[N] and T(*A),
  • an abbreviated syntax for identifying the containing `package`, `module`, `class`, or `interface`,
  • inline variable defininition in switch
  • the ability to directly import members of a singleton object,
  • relaxation of type constraint checking where unnecessary to ensure soundness, and
  • experimental support for type functions (higher-order generics) and references to generic functions (higher-rank polymorphism).

Language module

For Ceylon 1.2, the following new APIs were introduced to the language module:

  • the map() and set() functions allow creation of immutable Maps and Sets with no dependency to ceylon.collection,
  • distinct, frequences(), group(), tabulate(), and summarize() were added to Iterable,
  • getOrDefault(), defaultNullItems(), and coalescedMap were added to Map,
  • Collection.permutations() was added,
  • formatFloat() was added,
  • the Contextual interface was added, a cross-platform abstraction of thread-local values,
  • some operations of List were split out onto the new SearchableList interface, and
  • arrayOfSize() was deperecated and replaced with the constructor Array.ofSize().

Furthermore, some native implementation code has been rewritten in Ceylon using native.

Compiler and command line tools

Enhancements to the Java compiler include:

  • much improved interoperation with Maven, including support for overriding module metadata with overrides.xml, and --flat-classpath and --auto-export-maven-dependencies,
  • all compiled classes are now Serializable and have default constructors, allowing much smoother interoperation with certain Java frameworks,
  • improved interoperation with Java annotations, and
  • basic support for interoperation with libraries written in Scala.

The JavaScript compiler now supports type functions, allowing the use of higher-order and higher-rank polymorphism in Ceylon. These experimental features are not yet supported by the Java compiler.

There are several new features and improvements to the command line toolset:

  • the ceylon war command repackages a module as a Java EE WAR archive,
  • the ceylon browse command opens module documentation in the browser,
  • multiple commands can be given simultaneously, for example ceylon compile,doc,run com.redhat.hello,
  • ceylon help command and ceylon --help now page output by default, and
  • the ceylon command architecture now supports writing plugins in Ceylon.


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

  • a brand new debugger for Ceylon,
  • extensive support for new language features including constructors and native,
  • improvements to the powerful Change Parameter List refactoring,
  • the Inline refactoring can now inline a type alias,
  • filtering of packages from searches and completions,
  • many new quick fixes and assists,
  • Paste Java as Ceylon,
  • the popup Outline can now show inherited members,
  • the redesigned Open Declaration dialog now shows documentation,
  • keyboard shortcuts were added for certain quick assists,
  • support for Eclipse's new dark theme,
  • refactored preferences pages, with much greater customizability, including
  • two new alternative syntax highlighting themes, along with an alternative icon set.

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.


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

This release introduces two new platform modules:

  • ceylon.transaction provides support for distributed transaction processing, and
  • ceylon.regex provides regular expressions.

Along with several API enhancements and bugfixes, including:

  • ceylon.time now has functions for parsing ISO 8601 formatted dates, times, and datetimes,
  • ceylon.locale now supports formatting zoned times, and parsing dates and times,
  • now has javaClassFromDeclaration(),
  • now has redirect(), and its Uri is now immutable, and
  • the collection types in ceylon.collection now offer additional named constructors.

OpenShift cartridge

The Ceylon cartridge for OpenShift has been improved and updated to support Ceylon 1.2.


You can try Ceylon using the redesigned Web IDE, now rewritten in Ceylon, and 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.


The Ceylon community site,, 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.


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

Migrating from Ceylon 1.1

Migration from Ceylon 1.1 is easy. To recompile a module for 1.2:

  • 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.1.0" to "1.2.0" .
  • If it imports any platform-native module, annotate its module declaration native("jvm") or native("js"), depending upon the target platform. This step does not apply to cross-platform modules.
  • If, when recompiling, you encounter errors on assert statements, try removing the assertion (the improvements to flow typing now make some type assertions redundant).


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.

Why you might want to choose Ceylon

In a couple of days Ceylon 1.2 will be released. Ceylon 1.2 is out now, after a year of development. That’s exciting for us, but we think it would be interesting to summarize our thoughts about why you should be excited about Ceylon, and why you might consider it over other programming languages designed to run on the Java and JavaScript virtual machines.

Ceylon is a rather ambitious programming language, so sometimes when people ask us to summarize its advantages, it can be a bit difficult to know where to start!

A truly cross-platform language

Ceylon is a language that is equally at home on the JVM and on any JavaScript VM. Furthermore, implementation of a compiler backend for the Dart VM is already quite advanced, and work has begun on a native backend based on LLVM. The architecture of the compiler and tooling make addition of a new runtime environment, if not easy, at least straightforward.

Also important: Ceylon is rigorously defined by a complete language specification. The very act of writing a specification forces the language designer to really think through the semantics and corner cases, and acts as an essential reference as to what the behavior of the compiler should be.

Unlike other languages designed first for the JVM and then, belatedly, ported to JavaScript, Ceylon doesn’t feature JVM-specific numeric types with semantics that aren’t relevant to—or can’t be honored on—other VMs. And its language module isn’t polluted with dependencies to types like java.lang.Exception that don’t exist in other runtime environments. Instead, Ceylon’s language module completely abstracts the underlying runtime, and offers a set of elegant APIs that vastly improve on those available natively.

But this abstraction doesn’t come at the cost of lowest-common-denominator performance characteristics. On the contrary, you can expect Java-like performance when Ceylon executes on the JVM, Dart-like performance when Ceylon executes on the Dart VM, and JavaScript-like performance when Ceylon executes on a JavaScript VM like Node.js.

Nor does this abstraction limit the potential for interoperation with native code. Ceylon features excellent interoperation with Java and Maven, and it’s very easy to use most Java libraries in Ceylon. Similarly, Ceylon’s battery of dynamic constructs make interoperation with native JavaScript straightforward. With the new native functions and classes in Ceylon 1.2, it’s even possible to write a cross-platform module that interoperates with native Java and JavaScript code!

Finally, Ceylon's module system is already compatible with OSGi, with Maven, with Vert.x, with npm, and with requirejs. When Jigsaw finally arrives, we'll support it too.

This all amounts to an impressive engineering achievement, especially when taking into account the sophistication of the language itself.

Truly disciplined static typing

Chances are you have some experience writing code in a language with static typing. In combination with the right tooling, static typing makes code more robust, more understandable, and much more maintainable. But most languages go out of their way to include features and APIs which undermine their own static type system. A handful of languages such as ML and Haskell eschew this, offering a principled, disciplined approach to static typing. And programmers working with these languages report a curious thing: that their programs have a strange tendency to work first or second time they run them. Sure, it takes a little longer to produce a program that the compiler accepts, but once the compiler is satisfied, so many common bugs have already been eliminated, that the program is often already correct or at least almost correct.

Ceylon follows this same philosophy and, even though it’s a very different sort of language to ML, our experience is that our programs have the very same tendency to just work, almost immediately. You surely won’t believe this until you experience it yourself.

Ceylon’s type system itself is state-of-the-art, including generic types with both use-site and declaration-site covariance and contravariance, mixin (multiple) inheritance, principal instantiation inheritance, sum types, disjointness analysis, experimental support for higer-order and higher-rank generics, and, best of all, union and intersection types.

Union and intersection types

Ceylon was the first modern language to introduce a full implementation of union and intersection types, and the first language to realize that union and intersection types make flow-typing and type inference, especially generic type inference, very much simpler, more predictable, and more elegant. As of today, it’s still the language with the most sophisticated support for unions and intersections.

What’s most difficult to explain to folks who’ve never written any significant amount of code in Ceylon is just how powerful union and intersection types really are. Far from being an exotic construct that you encounter occasionally in tricky library code, they form an essential part of the everyday experience of writing code in Ceylon, and there is almost no significant Ceylon program which doesn’t use union types somewhere. It’s no exaggeration to say they will totally change the way you think about types.

Flow-sensitive typing

Ceylon was also the first modern language to embrace the notion of flow-sensitive typing, where the conditional logic in the body of a function affects the types inferred by the compiler. This approach eliminates a significant amount of verbosity and a significant number of runtime type casting errors. In combination with Ceylon’s powerful coverage and disjointness analysis, it also helps detect certain other kinds of logic errors.

The cleanest solution to the problem of null

The null value has perplexed language designers for decades. For a long time the “best” solution to the problem was an ML- or Haskell-style Maybe type, which offered type safety and eliminated the hated “null pointer” error. That solution works quite well for languages without subtyping, but it’s not the best approach for a language with subtyping and union types. Ceylon’s approach to null is just as type safe, but, with flow-sensitive typing, is more user-friendly, and it doesn’t require the overhead of separate Option-style wrapper objects. Unlike some other languages, Null isn’t a special case in Ceylon’s type system. Rather, it’s just one further example of the power of union types.

An elegant and powerful representation of tuple and function types

Like most other modern languages, Ceylon features tuples and function references. Unlike other languages Ceylon doesn’t represent these things as special cases in the type system, nor as an explosion of interface types, one for each tuple/function -arity. Instead, there is just one class Tuple, and one interface Callable which expresses function types in terms of tuple types. This approach allows the language to abstract over tuple or function -arity, and write higher-order functions that simply can’t be expressed in many other modern languages.

Reified generics

Along with Gosu, Ceylon is one of only two languages to offer reified generics on the JVM. And it’s the only language to offer reified generics on JavaScript virtual machines. You’ll sometimes run into attempts to “backsplain” the lack of reified generics in Java or other JVM languages: claims that reified generics perform badly, aren’t useful, or don’t work correctly with variance or with higher-order generics. Ceylon is an existence proof that none of these assertions is true.

The system of reified generics backs Ceylon's unique typesafe metamodel, which enables powerful runtime metaprogramming (reflection). It also makes debugging easier: you can see the runtime type arguments of every generic type or generic function in the Ceylon debugger!

A clean, efficient, highly readable syntax

A program written in idiomatic Ceylon is usually much more compact than the same program written in Java. But it’s also usually more readable. Ceylon’s syntax appears, at first glance, to be rather boring and conservative: it uses familiar (and cleaner) prefix type annotations instead of postfix types; it uses plain English keywords instead of cryptic strings of symbols; its naming convention eschews the use of abbreviations. When you look at a program written in Ceylon, you’ll probably understand more or less what it’s doing, even if you have only a passing familiarity with the language.

But that first impression misses a surprising amount of syntactic flexibility. Type inference, named arguments, comprehensions, tuples and sequences, “fat arrow” function definitions, anonymous functions, let, switch, if, case, and object expressions, flow-sensitive typing, and a very powerful facility for stream processing all work together to lend a level of expressiveness rarely seen outside of dynamic languages.

Operator overloading is a feature that, while useful, is widely abused in languages that offer it in unadulterated form. Instead of untrammelled operator overloading, Ceylon supports operator polymorphism, a more disciplined approach, where its operators have fixed, well-defined semantics, but are defined in terms of interfaces that user-written types may satisfy. Thus, you can have the + operator apply to your own class, but it always means some kind of addition-like operation.

We often don’t need to write down the types of things explicitly (type inference takes care of that), but when we do, Ceylon features a uniquely sophisticated expression syntax for types, along with type aliases, eliminating the verbosity of generic type declarations in other languages.

Awesome modularity and tooling

Ceylon’s suite of command line tools, including an incremental compiler, program runner, test runner, documentation compiler, code formatter, and WAR archive packager, are all accessible via the ceylon command, which features a plugin architecture, and excellent usability.

But Ceylon really comes into its own when authoring code using its powerful Eclipse-based IDE. Ceylon’s IDE has a feature set that easily surpasses other modern languages, and competes with much more mature languages like Java and C#. For those who prefer IntelliJ, an IntelliJ-based IDE is already in the works, with a first release planned in the next few months.

If you’ve ever spent time waiting for mvn to finish, you’ll immediately appreciate Ceylon’s powerful module architecture, which comes fully integrated into the command line tools and IDE. Modularity is a problem that is utterly central to the discipline of software engineering, and Ceylon, at least arguably, does it better than any other language out there. You don’t usually need to interact directly with the module repository architecture, since the command line compiler, IDE, and runtime all know how to fetch dependencies transparently.

Finally, Ceylon Herd is an fantastic tool that makes it ridiculously easy to share your work with other Ceylon developers.

Seamless web development

Ceylon is evolving into a compelling platform for web development, allowing you to reuse code written for a Java server on the JavaScript client and vice-versa, while still interoperating cleanly with native code on both sides. With our new serialization facility, you'll be able to transparently move objects between client and server. The Ceylon SDK comes with a HTTP server module based on Undertow, and a transactions module based on JBoss Transactions, but if you're looking for something "heavier", Ceylon modules can already be deployed on RedHat's OpenShift cloud platform, on WildFly, or on Vert.x 2 (with Vert.x 3 support coming soon). Alternatively you could use Ceylon in Node.js!

Developing web applications in Ceylon is actually enjoyable. With Ceylon, you'll spend much less time redeploying and/or refreshing things, or wrestling with inadequate tooling, and more time focused on writing elegant code.

A helpful and open-minded community

The Ceylon community is friendly and helpful, and you can usually get your questions answered quickly at just about any time of day. And we're extremely open to feedback, and don't mind explaining the reasoning behind decisions we've made. Of course we have the traditional mailing lists like any other open source project, but actually we're much more active on Gitter and on the GitHub issue tracking system. So come join us on our Gitter channel, and ask us anything!

If you're motivated to contribute, there's plenty of places to get involved. Some fairly significant parts of the Ceylon ecosystem were originally written by community contributors. Currently, the development of two new compiler backends is being driven by the community. Note that a whole lot of development, including the IntelliJ IDE, and the new compiler backends, is now being done in Ceylon, so you can learn Ceylon by contributing to the Ceylon project itself!