Team blog

Ceylon 1.3.1 is now available

Ceylon 1.3.1 is a significant minor release of the Ceylon language, with over 140 issues closed. This is the first release of Ceylon which supports interoperation with Java 8 lambdas and streams, with RxJava, and with Spring Boot. This release also introduces support for static members.

This release of Ceylon has been tested with a wide variety of Java libraries and frameworks, including:

Example code demonstrating the use of these frameworks is available.

Compared to previous releases of Ceylon, the use of Java frameworks based on reflection is now much more transparent, and integration with multi-module Maven-based platforms and frameworks is now much easier to configure.

The Ceylon tour has been extensively updated, especially the sections addressing interoperation with native Java and JavaScript, and with the module system.

Changes

Enhancements to the language and command-line distribution include:

  • static members in Ceylon classes
  • interoperation with Java 8 lambdas—ability to pass Ceylon functions to Java SAM types
  • local import statements
  • support for spread operators * and *. with java.lang.Iterable and Java arrays
  • literal tuples in cases of a switch
  • small Characters
  • new Maven interop mode --fully-export-maven-dependencies for projects depending on multi-module platforms like Spring Boot
  • support for POM-only Maven artifacts
  • new Java EE-friendly compiler mode, making it easy to use Java frameworks that depend on reflective direct access to fields
  • ability to pass Ceylon metamodel to Java methods accepting java.lang.Class
  • ability to pass Ceylon strings to Java methods accepting java.lang.CharSequence
  • improved treatment of null values originating in calls to native Java
  • several bugfixes to relating to interop with overloaded Java methods
  • new command line options: --java, --incremental, and --include-dependencies

Naturally, the release incorporates many more bugfixes and minor enhancements.

IDE Changes

Ceylon IDE 1.3.1 for IntelliJ and Eclipse resolves more than 110 issues, and adds support for running and debugging Ceylon programs on WildFly Swarm.

SDK Changes

Exactly 15 issues affecting the Ceylon SDK have been fixed, and the new platform modules ceylon.interop.spring and ceylon.interop.persistence were introduced. New 1.3.1 releases of the platform modules are available in Herd.

Migration

  • For the JVM, this release is backwards-compatible with all previous releases of Ceylon since 1.2.0.

  • For JavaScript, this release is backwards-compatible only with the previous two releases (1.2.2 and 1.3.0).

Ceylon 1.3.1 is backward-compatible with Ceylon 1.3.0, and so it's not necessary to recompile or change dependencies. However, upgrading to version 1.3.1 of any Ceylon platform module is recommended.

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 IDE supporting both IntelliJ IDEA and the Eclipse platform.

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, a "fat" JAR 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, which also supports interoperation with OSGi, Jigsaw, Maven, and npm, and
  • the language module, our minimal, cross-platform, foundation-level API.

Available separately:

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.

Community

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

You can follow @ceylonlang on Twitter.

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.

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, Gilles Duboscq, Tomasz Krakowiak, 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, Oliver Gondža, Stephen Crawley, Byron Clark, Francisco Reverbel, Jonas Berlin, Luke Hutchison, Nikita Ostroumov, Santiago Rodriguez, Sean Flanigan, Schalk W. Cronjé.

Ceylon 1.3.0 is now available

Ceylon 1.3.0 is a major release of the Ceylon language, with over 330 issues closed. This is the first release of Ceylon which supports Android development, the Node Package Manager (npm), and Wildfly Swarm.

  • For the JVM, this release is backwards-compatible with all releases of Ceylon 1.2 (1.2.0 to 1.2.2).

  • For JavaScript, this release is backwards-compatible only with the previous release (1.2.2).

Ceylon IDE 1.3.0 is now available for the two leading Java development environments:

Ceylon IDE for IntelliJ was designed for high performance in large projects with many Java dependencies, and is currently the best-performing IDE for Ceylon.

Changes

Enhancements to the language and command-line distribution include:

Naturally, the release incorporates many more bugfixes, minor enhancements, and performance improvements.

Support for Docker

Docker images for Ceylon are now available, making it very easy to run Ceylon programs in a Docker container.

IDE Changes

Ceylon IDE for IntelliJ is a brand-new development tool for IntelliJ IDEA and Android Studio, featuring incremental error reporting, code completion, basic refactoring, many intention actions, sophisticated navigation, searching, type hierarchy and file structure, online documentation, full integration with Ceylon Herd and much, much more.

Ceylon IDE for IntelliJ is written mostly in Ceylon, and reuses the Ceylon IDE Common project, the core of Ceylon IDE for Eclipse, which was completely rewritten in Ceylon.

Almost 60 issues were fixed in Ceylon IDE for Eclipse, and code completion was redesigned around a non-blocking approach which is much more responsive in large projects. In addition, improvements to the typechecker have resulted in significantly lower memory usage.

SDK Changes

Exactly 40 issues affecting the Ceylon SDK have been fixed.

Migration from Ceylon 1.2.2

Ceylon 1.3.0 is backward-compatible with Ceylon 1.2.2, and so it's not necessary to recompile or change dependencies. However, upgrading to version 1.3.0 of any Ceylon platform module is recommended.

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 IDE supporting both IntelliJ IDEA and the Eclipse platform.

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, a "fat" JAR 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, which also supports interoperation with OSGi, Jigsaw, Maven, and npm, and
  • the language module, our minimal, cross-platform, foundation-level API.

Available separately:

  • updated versions of the platform modules that comprise the Ceylon SDK,
  • a code formatter as a plugin for the ceylon command,
  • a plugin for the ceylon command that supports compilation and execution for the Dart VM, and
  • two full-featured integrated development environments: for Eclipse and IntelliJ IDEA.

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.

Community

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

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, Gilles Duboscq, Tomasz Krakowiak, 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, Oliver Gondža, Stephen Crawley, Byron Clark, Francisco Reverbel, Jonas Berlin, Luke Hutchison, Nikita Ostroumov, Santiago Rodriguez, Sean Flanigan, Schalk W. Cronjé.

Ceylon Bootstrap

Ceylon 1.2.2 was released back in March, and at the time it shipped with a new feature that did not make a lot of noise, but I think it's worth explaining it a bit more in this blog.

In general Ceylon developers have to download the Ceylon distribution in order to compile Ceylon code, and so do Ceylon users. When you check out a Ceylon project you have to make sure you're using the right version of the Ceylon distribution to compile it, and switching Ceylon distribution can be a bit too involved on some Operating Systems.

To solve that issue, Tako has implemented the ceylon bootstrap tool, very heavily inspired by the Gradle Wrapper, which allows you to generate a small script in your Ceylon project which your users and developpers can use to automatically download the right Ceylon distribution and cache it for future use.

Let's try it out by generating a new Ceylon project (on a machine with a Ceylon 1.2.2 distribution, this is a chicken and egg problem and we have to start somewhere):

$ ceylon new hello-world --ant=no --eclipse=no myproject
Enter module name [com.example.helloworld]: 
Enter module version [1.0.0]:

Now let's check that it compiles and runs:

$ cd myproject
$ ceylon compile,run com.example.helloworld
Note: Created module com.example.helloworld/1.0.0
Hello, World!

Excellent! Now let's add the Ceylon bootstrap tool:

$ ceylon bootstrap
$ ls ceylonb*
ceylonb  ceylonb.bat
$ ls .ceylon/bootstrap/
ceylon-bootstrap.jar  ceylon-bootstrap.properties

As you can see, we've created two ceylonb scripts (one for Unix, one for Windows), and a new configuration folder for those scripts containing a tiny jar (24k) and a settings file which points to the distribution to use:

$ cat .ceylon/bootstrap/ceylon-bootstrap.properties 
#Generated by 'ceylon bootstrap'
#Tue Aug 02 17:29:39 CEST 2016
distribution=https\://downloads.ceylon-lang.org/cli/ceylon-1.2.2.zip

These scripts and folders should be committed to your project code, so they can be used by others.

Now, whenever someone checks your project out, they can just use the provided ceylonb script to work rather than pre-install the Ceylon distribution:

$ ./ceylonb compile,run com.example.helloworld
Downloading Ceylon... 100%
Note: Created module com.example.helloworld/1.0.0
Hello, World!

The first time you run this, it will download the desired Ceylon distribution to ~/.ceylon/dists, but from then on, whenever you invoke ceylonb it will reuse that distribution without downloading anything. Even other projects using the same distribution will be able to use it.

As I said, Gradle Wrapper users are used to this, but still, it's a really good idea and there's no reason why programming languages couldn't do the same!

Status Report: Ceylon TypeScript Loader GSoC project

TL;DR: coming along, won’t be done in time for official GSoC deadline, I’ll just keep working.

(Note: this is a GSoC status report. The entire project is work in progress, and if you’re looking for a something finished, you’ll have to wait until the project is released, at which point there will be a proper announcement.)

For this year’s Google Summer of Code, I am working on adding TypeScript support to the Ceylon JavaScript backend. The goal is to have a tool that, given a TypeScript module (one or more files), produces a Ceylon module for the JavaScript backend. The JS code of that module will just be the TypeScript compiler’s output (plus possibly some metamodel stuff), but the tool will also add model information that will allow you to use the TypeScript module from Ceylon like any other Ceylon module, without needing to use dynamic blocks or having to declare your own dynamic interfaces.

I actually started work on this tool a few months before GSoC, in January this year. I wrote the first iteration of the program in TypeScript in order to be able to interact with the TypeScript compiler (which is also written in TypeScript). The goal of that first iteration is just to be able to load the TypeScript compiler itself, so that I can then use that module (tsc) from Ceylon and write the second (and probably final) iteration of the program in Ceylon.

This first iteration of the program was mostly finished, at least good enough that I could start writing the second iteration, shortly after the GSoC work period officially started. I had hoped to start with the second iteration exactly at the start of GSoC, but while there had been good progress with my own simple test module, tsc held a couple of nasty surprises that I hadn’t anticipated and that I had to work around. It also turned out that I had made a couple of very bad decisions early on:

  • I chose to operate on the parsed syntax tree instead of the typechecker model. How I ever expected this to work, I have no idea, but problems quickly became obvious:

    • When I see a type reference, like Element, I have to know if this refers to a type parameter, a type from the same module, or perhaps one from another module. The type I store in the model must be fully qualified.
    • To represent a type with type arguments, the JS model lists the type arguments along with their type parameter name. So to transform a type like Array<string>, I have to know that Array’s first type parameter is called Element.
    • TypeScript features type inference. Of course, I have to know the inferred type so that I can put it into the model.
  • To get a first version out quickly, I just wrote directly to the -model.js file. The model is mostly JSON, so this meant some ugly manual comma management when it turned out there are some declarations where I don’t emit anything (such as index signatures).

There are some lovely commit messages in the git log, with phrases like “totally hacky”, “should be enough for now”, “this is where it all falls apart”, “add fake support”, “horrible hack”, and “How could I possibly ever think that it’s possible to write this loader without access to tsc’s model, purely based on the AST?” I am very glad that I get to learn from these mistakes in the second iteration :)

Now, writing the second iteration also turned out to be trickier than I’d thought. I had (still have) a Ceylon version of the TypeScript compiler, the tsc module, but it’s difficult to work with from Ceylon. Two problems mainly held me up:

  1. TypeScript supports optional members: { name?: string } is the type of a value that might have a member name (containing a string), but might also have no such member (undefined). The Ceylon runtime doesn’t like this at all and breaks in many different and difficult-to-debug ways; the only solution I found was to not emit such members at all. To access them without “attribute does not exist” typechecker errors, I use eval inside dynamic blocks, which leads us to the second problem.
  2. Whenever a dynamic value (such as the return value of an eval call) is assigned to a Ceylon type, the runtime “dresses” the value with the type that it’s being assigned to (adds RTTI). If this is not the most precise type of the value (say, you dressed the value with Node and later want to use it as a VariableDeclaration), you have to jump through some hoops to fix this – a simple assert (is VariableDeclaration node) won’t work, since Ceylon doesn’t like to narrow these dressed types.

I now have workarounds for both problems, but they took a while to find, and of course I shouldn’t have to work around them in the first place, so I’ll have to teach the Ceylon JS backend to “do the right thing” eventually. (I also have to do that in many other cases, since the Ceylon JS “ABI” differs significantly from plain JS – Ceylon classes aren’t instantiated with new, toplevel values compile to functions, arrays aren’t arrays, etc. etc.)

Right now, the second iteration supports:

  • toplevel values,
  • toplevel functions (no parameters), and
  • the string type.

That’s it. But, unlike the first iteration, it supports this without needing to add any JS code (I’ve already taught the compiler to access the toplevel values as values and not functions). Currently, some JS code is added (metamodel stuff), but I’m not sure if I’ll actually keep that. We could say that what, are you crazy, why would TypeScript modules support the metamodel?, and then the JS file would just be the unaltered tsc output, and the tool would only add the -model.js file. This would probably make working with declaration files easier (where the JS isn’t generated by tsc – one of many problems I haven’t even begun to think about yet).

I’m fairly confident that I’ll be able to add support for most “basic” features – type references and other primitive types, type parameters and arguments, parameters, classes, interfaces, methods, attributes – without too much trouble. After that, all bets are off. TypeScript supports some crazy features, like string types ("foo" | "bar" | "baz" is a valid type) and type guards (pet is Fish is a valid return type, a weird inversion of Ceylon’s is Fish pet conditions), and I have no idea how well we can support them. I will also need to make more changes to the JS backend and runtime, and I don’t know how difficult those will be.

There are about four weeks left before the official GSoC deadline, and I’ll be on vacation for one of them. I hope that the “basic” support will be done until then, but there’s zero chance that the project will be in shippable state. I’m not too worried about that – I’ve worked on the project before GSoC started, I’ll continue to work on it after GSoC ends, just like I did with ceylon.ast two years ago. And, just like two years ago, I should have more time after GSoC ends, because GSoC is actually scheduled pretty weirdly for me, where I still have lectures for most of it and it barely overlaps with my semester break. I should be free to work on this project for most of August, September, and the first half of October, and hope to arrive at something that can actually be released somewhere before the end of that period.

Modularity Changes

TL;DR: This article describes the modularity changes in the Ceylon run-time and distribution, in order to make them lighter at run-time. Skip to the Final runtime dependencies section if you just want the outcome.

As we initially expected most Ceylon users to run their code using the ceylon run command, we figured that since they have the Ceylon distribution installed, it does not matter if they depend on more modules from that distribution than strictly necessary. Those modules had to be there anyway, so it would not save any bandwidth to reduce those dependencies.

Naturally, we were wrong, and between the Ceylon Eclipse or IntelliJ IDEs, running Ceylon on OpenShift, WildFly, Vert.x or on Android, people started running Ceylon without the distribution installed, using just the standard java runner. It became soon apparent that we had to untangle those dependencies to make the runtime requirements lighter.

Historically we had the following modules:

  • common module used by other modules
  • typechecker (the shared compiler front-end)
  • Java compiler back-end
  • JavaScript compiler back-end
  • module repository system
  • JBoss modules runtime

The model module

When we implemented reified generics, we had to add subtyping to the runtime, so that we'd be able to figure out if is T bar was true or not. The easiest thing at the time was to "just" depend on the typechecker (compiler front-end) which dealt with the language model and subtyping, and the Java compiler back-end, which had infrastructure to load a language model from JVM information such as class files, or in this case reflection.

This essentially made the runtime depend on the compiler front-end and back-end, which we realised was not ideal, so during the Ceylon 1.2 development, we extracted all model description, loading and subtyping to a new ceylon-model module, but we did not have enough time to do more and so these dependencies remained due to other causes.

Supporting Java 9

During our work on supporting Java 9 / Jigsaw modules in Ceylon, it became clear that having kept our "fork" of javalang tools (that we use for javac) under its original package name would not work anymore, we renamed its package and used the opportunity to prune away parts of the java tools we did not use. We also extracted the class-file reader part to its own module so we could use it outside of the compiler to remove our dependency to jandex (a class-file scanner).

Finally, when we created the ceylon jigsaw tool (which populates a folder with the jar files required by a Ceylon module, to run it on a Java 9 VM) it became evident that the runtime still depended not just on the compiler front-end and Java back-end, but even on the JavaScript back-end, which frankly made little sense in most JVM executions.

These dependencies were due to the Ceylon Tool Provider API having snuck into the ceylon.language module as a convenience (at the time). Since that allowed you to compile and run Ceylon programmatically for both Java and JavaScript back-ends, it had to depend on the tools.

We decided to split the Ceylon Tool Provider into its own module and got rid of the final dependencies from the language module to the compilers and typechecker, but had no more time to get rid of further dependencies such as JBoss Modules and Aether in time for Ceylon 1.2.2.

Supporting Android

Initial work on running Ceylon on Android revealed that what passes for small dependencies on ordinary JVM executions, or even on Java EE deployments, was not an option on Android where every method counts.

At this point we had to bite the bullet and make every non-required transitive dependency go.

We noticed that the old common module had grew to include the Command-Line Tooling API that makes the ceylon command and its subcommands and plugins work. That in turn depended on a Markdown renderer used by ceylon doc. It was pretty trivial to extract it to its own module because this was never used in Ceylon user programs.

Next in line was our Shrinkwrap Resolver dependency, which our module repository system uses to interoperate with Maven repositories. This was a fat-jar with all its dependencies included, including some Apache Commons modules, and an outdated version of Eclipse Aether. That fat-jar had already been problematic in our Maven module, which already had its version of Aether, so getting rid of the fat-jar was a good idea. We also realised that some of its Apache Commons dependencies were already included outside the fat-jar in our distribution repository, so there was that duplication to fix too.

So what we did was remove the Shrinkwrap Resolver dependency and use Aether directly, by incorporating all its subcomponents into our distribution. It turns out that because the latest version of Aether requires Google Guava, our distribution grew in size rather than shrink (that jar is huge). But to offset that, we made the Aether dependency optional, and made sure it was possible to run Ceylon without it as long as there was some compilation step beforehand that provided all the Maven dependencies that you may use in interop. ceylon fat-jar or ceylon jigsaw would do that for you, for example.

Our module repository system also provided support for writing to WebDAV or Herd repositories, which required some dependencies on Apache Http Client or Sardine, and we made these dependencies optional as well, because at runtime your Ceylon program is very unlikely to write to HTTP repositories. This is something only the compiler and other tools do.

We also removed a dependency to JBoss Modules from the language module using abstraction, since that platform was optional and never used on Android or other flat-classpath runtimes.

Finally, the language module only had one dependency left on the (much slimmer) module repository system via the presence of the Main API in there, and we moved that class to its own module.

Final runtime dependencies

After all this pruning, the language module on the JVM is back down to requiring the following set of transitive dependencies:

  • common (small and free of tooling and dependencies)
  • model (which depends only on the class-file reader)
  • class-file reader

So your Ceylon module will only depend on four jars (these three and the language module), the sum size of which is 2.4 Mb, which is much smaller than initially, and has dramatically less methods, at around 17148 methods. This is still too much, but can be brought down by tooling such as ProGuard to remove unused classes. Remember this includes a runtime for an entire language, so it's not that big, all things considered.

SDK changes

In order to be able to use Ceylon's HTTP client on Android, we also split up the ceylon.net module from the Ceylon SDK into client and server modules. Otherwise the HTTP server and its dependencies were too much drag for Android's method count.