Team blog

Ceylon 1.0 beta

After more than three years of development, Ceylon is now feature-complete. Ceylon 1.0 beta implements the whole language specification, providing the capability to execute Ceylon programs on both Java and JavaScript virtual machines and to interoperate with native code written for those platforms. This release includes:

  • a complete formal 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, 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, and
  • the language module, our minimal, cross-platform foundation of the Ceylon SDK.

Simultaneously, we're releasing Ceylon IDE 1.0 beta, the latest iteration of our full-featured Eclipse-based development environment.

runas

New features of the language

This release introduces the following new language features, along with many bugfixes:

  • annotations and annotation constraints,
  • a typesafe metamodel,
  • "static" method and attribute references,
  • try with resources,
  • support for strings, integers, and characters in switch,
  • support for named unicode characters in string and character literals,
  • the ** scaling multiplication operator,
  • nonempty variadic parameters, and
  • a new improved syntax for calling concrete members of inherited interfaces.

The new features are summarized here.

metamodel

New features of the IDE

This release of the IDE introduces performance improvements, many bugfixes, and:

  • support for launching Ceylon programs on the module runtime,
  • paste-with-imports, and autoindentation on paste,
  • integration with Eclipse's built-in file and package refactorings,
  • inline "linked-mode" rename, and rename support for references in documentation strings,
  • improvements to autocompletion, including "linked-mode" argument completion,
  • much improved integration for Eclipse's merge viewer,
  • integration with the commandline toolset's configuration file format,
  • several new quick fixes and assists, including new quick assists for adding and changing import aliases, and
  • a new editor preferences page.

You can see screenshots of the new release here.

autocomplete

rename

Community

The Ceylon community site includes documentation, and information about getting involved.

http://ceylon-lang.org

SDK

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

https://herd.ceylon-lang.org

Source code

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

https://github.com/ceylon

Issues

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

Acknowledgement

We're deeply indebted 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 this release:

Gavin King, Stéphane Épardaud, Tako Schotanus, Emmanuel Bernard, Tom Bentley, Aleš Justin, David Festal, Flavio Oliveri, Max Rydahl Andersen, Mladen Turk, James Cobb, Tomáš Hradec, Michael Brackx, Ross Tate, Ivo Kasiuk, Enrique Zamudio, Roland Tepp, Diego Coronel, Brent Douglas, Corbin Uselton, Loic Rouchon, Lukas Eder, Markus Rydh, Matej Lazar, Julien Ponge, Julien Viet, 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, Paco Soberón, Sjur Bakka, Xavier Coulon, Akber Choudhry, Ari Kast, Dan Allen, Deniz Türkoglu, F. Meurisse, Jean-Charles Roger, Johannes Lehmann.

Ceylon M6 progress report

So it looks like it's time again for me to offer my usual lame excuses for another late milestone release of Ceylon. Well, I suppose all that really matters is: it's coming soon!

Ceylon M6 will be the first feature-complete implementation of the language specification, incorporating the following headline changes:

  • new syntax for invoking super-interface members,
  • nonempty variadic parameters
  • try with resources,
  • the ** scaling multiplication operator,
  • "static" member references,
  • metamodel and metamodel expressions, and
  • annotations.

We have not yet decided if support for serialization will make it into M6.

Invoking super-interface members

Previously, we were using a rather ugly and arbitrary syntax, for example, List::equals(that), to invoke an overridden member of a superinterface. Now we can just write:

super.equals(that)

except in cases where this is ambiguous (the member is ambiguously inherited from more than one supertype), in which case we can use the widening of operator to eliminate the ambiguity:

(super of List<T>).equals(that)

(We now treat super as a value whose type is the intersection of all immediate supertypes of the current type.)

Nonempty variadic parameters

You may now define a variadic function that requires at least one argument, for example:

String max(String+ strings) {
    value max = strings.first;
    for (string in strings.rest) {
        if (string>max) {
            max = string;
        }
    }
    return max;
}

The type of such a function is written String(String+), meaning, of course, Callable<String,[String+]>.

try with resources

This constuct works almost exactly like in Java. For example:

try (Transaction()) { ... }

Scaling multiplication operator

A top user request was support for "scaling" multiplication for vectors, matrices, durations, etc. We've introduced the interface Scalable and the ** operation to let you write things like:

Vector scaled = 2 ** vector;

Static member references

Static member references let us obtain a reference to a member of a type without providing an instance of the type. For example:

  • Person.name refers to the attribute name declared by the class Person, and
  • Object.equals refers to the method equals declared by the class Object.

The type of a static method reference is a function type where the first parameter list accepts an instance of the type that declares the member.

  • Person.name is of type String(Person), and
  • Object.equals is of type Boolean(Object)(Object).

Static attribute references are especially useful, since we can pass them directly to map():

Person[] people = .... ;
{String*} names = people.map(Person.name);

This functionality is already working.

The metamodel

We call Ceylon a "higher-order" language partly because functions, classes, methods, and attributes are typed values. For example, the class Person is a value of type Person(Name):

Person(Name) createPerson = Person;
Person person = createPerson(Name("Gavin", "King"));

However, Ceylon takes the notion of "higher-order" significantly further. The language lets us write typesafe code that reasons about the program itself, by providing a typesafe metamodel.

A metamodel expression is enclosed in backticks:

Class<Person,[Name]> personClass = `Person`;
Attribute<Person,Name> nameAttribute = `Person.name`;
Method<Object,Boolean,[Object]> equalsMethod = `Object.equals`;

We can use a metamodel to obtain the name and annotations of a declaration, or to query a type for members by their return type, parameter types, annotations, etc.

It's taking us a bit of work to get the metamodel just right, and that's the main thing that has been holding up the M6 release.

Annotations

Annotations are discussed here. The basic concept hasn't changed much in our initial implementation, but work is ongoing.

Ceylon IDE performance improvements

Ceylon already has a very complete IDE, based on Eclipse, with many features, that we're very happy with. And considering how young it is, it's quite amazing that it already has all these features, but in the race to create the IDE and add all the features we needed to it, we have always pushed back any work in making it work faster. As a result, we're now to the point where the IDE is mostly complete in terms of features, but pretty slow for large projects.

Luckily, pushing back the work on performance doesn't mean we didn't have ideas for how to improve it, and in fact we have a lot of ideas, and today I'm glad to announce that in collaboration with Serli (one of the companies sponsoring Ceylon), David Festal is going to spend the next six months working on fixing all the speed and memory issues we have with the Ceylon IDE. David is already behind a lot of work that went in the Ceylon IDE and has experience with not just the Eclipse APIs and the Ceylon plugin, but also all the Ceylon sub-systems that the IDE integrates, such as the type-checker, the backends and the module system.

Here are the major points David will be working on for the IDE:

  • Opening a Ceylon project should only generate Ceylon binaries if their source has changed.
  • Load module dependencies using their binaries if it turns out to be faster than using their sources.
  • Make the backend compiler use the already parsed and typechecked AST that is available in the IDE.
  • Beef up the automated test suite.
  • Share the loaded models for the Ceylon language module and the JDK modules across every project.
  • Research performance bottlenecks in the typechecker and backend if required.
  • Research and fix memory consumption on some architectures.
  • Improve incremental build when editing module files.
  • Add visual progress reporting of the module system.
  • Improve build visual progress reporting.

We believe that with David's availability and experience, all of these issues will be obliterated and we will have an incredibly fast Ceylon IDE even for large projects, at the latest for January 2014. The good news is that David will start this performance run as early as next week, and we will release new versions of the Ceylon IDE as soon as each improvement is stable enough to ship, so we can expect faster releases really soon.

Go David!

Java Reflection oddities with inner and enum class constructor parameters

Note: edited on 16/5/2013 to add info about enum constructors as well.

About Java inner classes

Java allows member classes (classes that are defined inside other classes), local classes (classes that are defined inside statement blocks) and anonymous classes (classes with no names):

class Outer {
    Object anonymous = new Object(){}; // this is an anonymous class

    // anonymous initialisation block
    {
        // this is a local class
        class Local{}
        Local l = new Local();
    }

    Outer() {
        // this is a local named class in a constructor
        class Local{}
        Local l = new Local();
    }

    void method() {
        // this is a local named class in a method
        class Local{}
        Local l = new Local();
    }

    // this is a member class
    class Inner{}
    Inner i = new Inner();
}

The Java Language Specification classifies member, local and anonymous classes as inner classes.

Implementation “details”

What the Java Language or Virtual Machine specifications do not tell you is how they are implemented. Some of it is explained already in other articles, such as how the Java compiler generates synthetic methods to allow these members classes access to private fields, which would not be allowed by the JVM.

Another implementation detail of inner classes that is handy to know is that inner class constructors take extra synthetic parameters. It is relatively well-known that the first synthetic parameter of an inner class constructor will be its enclosing instance, which it will store in a this$X synthetic field. This is valid for all three kinds of inner classes: member, local and anonymous.

But it is generally not known that local classes who capture non-constant final variables will require all these variables to be passed as extra synthetic constructor parameters (captured constant final variables will be inlined and not generate extra synthetic constructor parameters):

class Outer {
    void method() {
        final String constant = "foo";
        final String nonConstant = "foo".toUpperCase();
        class Local{
            /* synthetic fields and constructor: 

            Outer this$0;
            String nonConstant;

            Local(Outer this$0, String nonConstant){
                this.this$0 = this$0;
                this.nonConstant = nonConstant;
            }
            */
        }
        Local l = new Local();
    }
}

Another example: Java enum classes

Java allows you to create enumeration classes, which is essentially little more than syntactic sugar to help you define a list of singleton values of a given type.

The following Java code:

enum Colours {
    RED, BLUE;
}

Is essentially equivalent to:

final class Colours extends java.lang.Enum {
    public final static Colours RED = new Colours("RED", 0);
    public final static Colours BLUE = new Colours("BLUE", 1);

    private final static values = new Colours[]{ RED, BLUE };

    private Colours(String name, int sequence){
        super(name, sequence);
    }

    public static Colours[] values(){
        return values;
    }

    public static Colours valueOf(String name){
        return (Colours)java.lang.Enum.valueOf(Colours.class, name);
    }
}

As you can see, it saves quite some code, but also adds synthetic fields, methods and constructor parameters. If you had defined your own constructor, with its own set of parameters, like this:

enum Colours {
    RED("rouge"), BLUE("bleu");

    public final String french;

    Colours(String french){
        this.french = french;
    }
}

You would have gotten the following Java code generated:

final class Colours extends java.lang.Enum {
    public final static Colours RED = new Colours("RED", 0, "rouge");
    public final static Colours BLUE = new Colours("BLUE", 1, "bleu");

    private final static values = new Colours[]{ RED, BLUE };

    public final String french;

    private Colours(String name, int sequence, String french){
        super(name, sequence);
        this.french = french;
    }

    public static Colours[] values(){
        return values;
    }

    public static Colours valueOf(String name){
        return (Colours)java.lang.Enum.valueOf(Colours.class, name);
    }
}

Luckily, enums can’t be inner classes, so they will not have an extra synthetic parameter inserted for the container instance to add to those two.

OK, but why should I care?

In most cases you don’t care, other than for your own curiosity. But if you’re doing Java reflection with inner or enum classes, there are a few things you should know, and because I haven’t found them listed or specified online, I thought it would be important to make a list of things to help others figure it out, because different compilers will produce different results in the Java reflection API.

The question is what happens when you use Java reflection to get a java.lang.reflect.Constructor instance for inner or enum class constructors? In particular, what happens with the methods that allow you to access the parameter types (pre-generics: getParameterTypes()), the generic parameter types (post-generics: getGenericParameterTypes()) and annotations (getParameterAnnotations()), and the answer is: it depends.

Suppose the following Java classes:

class Outer {
    class Inner {
        Inner(){}
        Inner(String param){}
        Inner(@Deprecated Integer param){}
    }
}
enum class Enum {
    ;// yes this is required
    Enum(){}
    Enum(String param){}
    Enum(@Deprecated Integer param){}
}

Here are the size of the arrays returned by these three reflection methods, on each of our constructor, and how they differ depending on the Java compiler used:

Outer.Inner.class
.getDeclaredConstructor()
Outer.Inner.class
.getDeclaredConstructor(
String.class)
Outer.Inner.class
.getDeclaredConstructor(
Integer.class)
getParameterTypes()
.length
1 2 2
getGenericParameterTypes()
.length
compiled with Eclipse
1 2 2
getGenericParameterTypes()
.length
compiled with Javac
0 1 1
getParameterAnnotations()
.length
1 2 1

And the results are consistent for our enum class:

Enum.class
.getDeclaredConstructor()
Enum.class
.getDeclaredConstructor(
String.class)
Enum.class
.getDeclaredConstructor(
Integer.class)
getParameterTypes()
.length
2 3 3
getGenericParameterTypes()
.length
compiled with Eclipse
2 3 3
getGenericParameterTypes()
.length
compiled with Javac
0 1 1
getParameterAnnotations()
.length
2 3 1

As you can see, the synthetic parameters are always included in getParameterTypes(), but are only included in getGenericParameterTypes() when compiled with Eclipse.

getParameterAnnotations() on the other hand, will always include synthetic parameters except when at least one of your constructor parameters are annotated.

With this info, you now understand the differences between the results of these methods, but so far I still haven’t found a way to determine which parameter is synthetic or not, because although you can make a good guess for the this$X synthetic parameter, which is required by every inner class, you have no way of knowing the number of non-constant captured variables that will end up as synthetic parameters to local class constructors.

JUDCon Boston 2013

Gavin, Emmanuel and I will be at this year's Boston JUDCon for a 4h Ceylon hands-on, split in two 2h parts on Monday, June 10th.

During this session, we will help you learn the Ceylon programming language, hand in hand, from downloading the tools, using the IDE, getting to know the various tools, the language SDK, all the way to running your own module repository and publishing your first Ceylon modules to it and to the official Ceylon module repository.

No edge of Ceylon required, though the audience should be familiar with the Java programming language.

The first part of the workshop (10:00am - 12:00pm) will get you familiar with the Ceylon IDE and its command-line tools, as well as the basics of the language: the new type system, how to work with lists, functional programming and how to write classes and interfaces.

During the second part (1:00pm - 3:00pm), we will examine more advanced topics, such as using the Ceylon SDK to write a REST client, and even as ambitious as writing the ceylon.html SDK module from scratch and publishing it on Herd, our module repository.

Please take the time to download, install and check the following things to make the hands-on as smooth as possible, since it's not fun to spend too much time on installation:

  • Install the Java 7 JDK, and configure it as the default JDK
  • Install the command-line distribution of Ceylon (M5 Version)
  • If you did not manage to configure Java 7 as the default JDK on Windows, define the JAVA_HOME environment variable in your systems properties so that it points to your JDK 7 installation
  • Check that the Ceylon command-line tools run: ceylon --version must print the correct version of Ceylon (M5)
  • Install Eclipse Juno and the Ceylon IDE (or using our update site)
  • Check that you can create a new Ceylon project from within the Ceylon IDE and that you can launch it as a Ceylon Application (make a demo project with Hello Word! to test)
  • Finally check that the Ceylon command-line tools work in your project as well: in your demo Ceylon project's folder, the ceylon compile demo command should compile your project (provided you named your Ceylon module demo), and ceylon run demo/1 (provided you named your version 1) should print Hello World!

Make sure you register, because this is going to be another great JUDCon!