Blog of Gavin King

Ceylon M5 and Ceylon IDE M5 now available!

Ceylon M5 “Nesa Pong” is now available for download, along with a simultaneous compatible release of Ceylon IDE. This is a huge release, with the following headline features:

  • a fully-reified type system with generic type arguments available at runtime,
  • direct interoperation with native JavaScript,
  • tuples,
  • several important syntax changes in response to community feedback and practical experience, and
  • a datetime module and an HTTP server.

You can download the Ceylon command line distribution here:

http://ceylon-lang.org/download

Or you can install Ceylon IDE from our Eclipse update site.

Language features

M5 is an almost-complete implementation of the Ceylon language, including the following new features compared to M4:

In addition, the language specification and documentation have been substantially revised and improved.

The following language features are not yet supported in M5:

  • the type safe metamodel
  • user-defined annotations
  • serialization

This page provides a quick introduction to the language. The draft language specification is the complete definition.

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.

Community

The Ceylon community site includes documentation, the current draft of the language specification, the roadmap, and information about getting involved.

http://ceylon-lang.org

SDK

The new platform modules are available in the shared community repository, Ceylon Herd.

https://herd.ceylon-lang.org

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, Xavier Coulon.

Ceylon in the browser

Last week, we met the Ceylon HTTP server, which we can use to serve dynamic (or even static) content over HTTP. But what about the client side? Well, today we're going to write a little HTTP client that runs in the browser, mainly as a way of showing off Ceylon's new dynamic blocks.

First, let's see the server, in a module named hello.server:

import ceylon.net.httpd { createServer, startsWith, 
                          AsynchronousEndpoint, 
                          Request, Response }
import ceylon.net.httpd.endpoints { serveStaticFile }

void run() {
    createServer{ 
        AsynchronousEndpoint { 
            path = startsWith("/sayHello"); 
            void service(Request request, Response response, 
                    void complete()) {
                response.writeString("Hello, Client!");
                complete(); //async response complete
            }
        },
        AsynchronousEndpoint {
            path = startsWith(""); 
            service = serveStaticFile("../client");
        } 
    }
    .start();
}

The server has two asynchronous endpoints, one of which simply serves up static content out of the directory ../client, and the other of which just responds to requests with the text Hello, Client!.

The entrypoint to our application is a HTML page.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-type" 
              content="text/html;charset=UTF-8"/>
        <title>Hello</title>
        <script type="text/javascript"
                src="script/require/1.0.8/require.js">
        </script>
        <script type="text/javascript">
            require.config({
                // location of our project's compiled modules
                baseUrl: 'modules',
                // locations of external dependencies here
                paths: {
                    // path to the Ceylon language module 
                    'ceylon/language': 
                        '/script/ceylon/language'
                }
            });
            //alias our hello module to 'h'
            require(['hello/client/1/hello.client-1'], 
                    function (hello) { h = hello; });
        </script>
    </head>
    <body>
        <div>
            <input type="submit" 
                   value="Say hello" 
                   onclick="h.hello()"/>
        </div>
        <div>
            <span id="greeting"/>
        </div>
    </body>
</html>

The page has a button which calls the hello() function of the Ceylon module hello.client.

We're using require.js to load our Ceylon modules. Unfortunately require.js doesn't really have a concept of module repositories like Ceylon does, which means configuring it to find all our compiled Ceylon is a bit fiddly. Nor does it feature very good error reporting which turns "fiddly" into "time-wasting". (The implementation of require() in node.js is a much better fit,
but unfortunately we don't have that in the browser.)

Finally, the module named hello.client has the following function:

shared void hello() {
    dynamic {
        value req = XMLHttpRequest();       
        void handleResponse() {
            if (req.readyState==4) {
                document.getElementById("greeting")
                        .innerHTML = req.status==200 
                                then req.responseText 
                                else "error";
            }
        }
        req.onreadystatechange = handleResponse;
        req.open("GET", "/sayHello", true);
        req.send();
    }
}

This function makes use of the native JavaScript API XMLHttpRequest to send an asynchronous request to our server, and then interacts with the browser's DOM. But how on earth can a statically typed language like Ceylon call a weakly typed language like JavaScript!?

Well, code that appears inside a dynamic block is optionally typed. That is, Ceylon will make use of typing information when it is available, but when it is not, it will just shut up and let you write almost whatever you like, as long as it's syntactically well-formed Ceylon code. Ceylon can't be certain that there's really a function called XMLHttpRequest, and it certainly can't be sure that it has a member named onreadystatechange, but it will just assume you know what you're doing.

Inside a dynamic block, you can even instantiate a "dynamic" object:

dynamic {
    void printGreeting(value obj) {
        console.log(obj.greeting + " " + obj.language);
    }
    value obj = value { greeting="Hello"; language="Ceylon"; };
    printGreeting(obj);
} 

Of course, inside a dynamic block, all kinds of typing errors can occur at runtime, things that the Ceylon compiler would usually detect at compile time. But the compiler at least protects you from having dynamic typing errors "leak" out of the dynamic block and into your regular Ceylon code by performing runtime checks when you assign a dynamically typed expression (that is, an expression of unknown type) to something with a well-defined static type.

Well, that's essentially all there is to our application, except for a couple of boring module and package descriptors. Here we can see a server written in Ceylon running in the JVM being called by a client written in Ceylon running in a web browser and interacting with the browser's native JavaScript APIs. I think that's pretty cool.

A note of caution: we're still working through some wrinkles in the semantics of dynamic, and dynamic is still not supported on the JVM (it will be, eventually). Nevertheless, this will be available as an experimental feature in Ceylon M5.

Ceylon HTTP server

One of the exciting new features coming to the Ceylon SDK in M5 is the HTTP server contributed by Matej Lazar. The HTTP server forms part of the module ceylon.net and is based on Undertow, a fairly new project that will serve up HTTP in future versions of JBoss.

The API is still evolving, but I can give you a taste of it with a little hello world program.

import ceylon.net.httpd { createServer, Endpoint, Response, Request }

void runServer() {
    //create a HTTP server
    value server = createServer {
        //an endpoint, on the path /hello
        Endpoint { 
            path = "/hello";
            //handle requests to this path
            service(Request request, Response response) =>
                    response.writeString("hello world");
        }
    };

    //start the server on port 8080
    server.start(8080);
}

Or, if you're the kind of person who gets their kicks out of squeezing things into one line:

import ceylon.net.httpd { createServer, Endpoint, Response, Request }

void runServer() => 
        createServer { Endpoint("/hello", 
                (Request request, Response response) =>
                        response.writeString("hello world")) }
        .start(8080);

(No, FTR, I would never write it like that.)

Oh, I almost forgot, you'll also need to import ceylon.net in your module descriptor:

module hellohttp '1' {
    import ceylon.net '0.5';
}

Of course, what you don't need is any kind of XML metadata or build script to package stuff up into deployment archives or copy archives to a deployment directory.

And it starts up in an instant, right from the commandline or IDE.

Reification, finally

Thanks to a bunch of hard work by Stef, Ceylon finally has fully reified types, that is, reified generic type arguments. You can now write stuff like this very contrived example:

"Check if the given value is an instance 
 of the given type."
Boolean check<T>(Anything o) => o is T;

"A string is a list of characters."
assert (check<List<Character>>("hello"));

"A string is a list of objects."
assert (check<List<Object>>("hello"));

"A string isn't a list of integers nor a 
 list of floats."
assert (!check<List<Integer>|List<Float>>("hello"));

This long-promised feature, promised almost two years ago, will be available in the upcoming M5 release of the language. The truth is that it's going to take a fair bit more work to do all the optimizations we plan in order to wring acceptable performance out of this stuff, but we've got a couple of clever ideas in this area, that I'm going to keep under wraps for now. ;-)

So why is reified generics important? Well, I took a brief stab at answering that question way back when, but since then we've spotted a couple of other compelling reasons. So lets take a quick look at one practical problem that is extremely difficult to solve without reified generics.

Ceylon's language module has an interface called Category

shared interface Category {
    shared formal Boolean contains(Object element);
    ...
}

A Category is an object that can "contain" other objects. Given an object, we can ask if it belongs to the category by calling contains(), or using the in operator.

Of course, collections are Categorys:

shared interface Collection<out Element>
    satisfies {Element*} &
              Category & 
              ...

Now, notice that the signature of contains() for a Collection<String> is contains(Object element), not contains(Element element). The reason for that is that we want collections to be covariant in their element type. I should be able to write the following:

Collection<String> strings = [ "hello", "world" ];
Collection<Object> objects = strings;
print(1 in objects);

Notice that on the last line, an Integer gets passed to the contains() method of a Collection<String>.

So the, without making use of reified generics, the default implementation of contains() defined by Collection would be as follows:

shared actual default Boolean contains(Object element) {
    for (elem in this) {
        if (exists elem, elem==element) {
            return true;
        }
    }
    else {
        return false;
    }
}

That's already kinda lame. If I have a Collection<String>, and contains() gets passed an Integer, we should be able to immediately return false like this:

shared actual default Boolean contains(Object element) {
    if (is Element element) {
        for (elem in this) {
            if (exists elem, elem==element) {
                return true;
            }
        }
    }
    return false;
}

But, well, whatever, that's merely a minor performance optimization, I suppose. But now consider the case of a Range. A Range is a kind of Collection whose elements are determined by two endpoints, which could potentially have thousands or millions or even more values in between! The above default implementation of contains(), inherited from Collection, would be so hideously expensive as to be actually wrong. So Range should refine the implementation of contains() as follows:

shared actual Boolean contains(Object element) {
    if (is Element element) {
        return includes(element);
    }
    else {
        return false;
    }
}

shared Boolean includes(Element element) =>
        decreasing then element<=first && element>=last
                else element>=first && element<=last;

The is Element element test requires reified generics. Without it, I can't be sure that the given value is a Comparable<Element>, so I can't compare the given value to the endpoints of the Range.

What I've shown here, for those interested in type systems, is that in a type system with declaration-site covariance, there are perfectly legitimate reasons to want to be able to test the runtime type of a value. Sure, ML and Haskell don't need to do this kind of thing, but those languages don't feature subtyping, and therefore don't have covariance. Object oriented languages are very different, so please take that into account before arguing that reified generics are unnecessary.

UPDATE: For more information about the implementation, see Stef's email here:

https://groups.google.com/forum/?hl=en&fromgroups=#!topic/ceylon-dev/mIrroqhcf7o

UPDATE 2: It was very remiss of me to not mention that we've had support for reified generics in the JavaScript backend for a while now. Thanks, Enrique!

Expressiveness

I just noticed a tweet by Paul Snively that I thought was interesting. I don't make it my practice to respond to tweets, simply because >99.9% of them are just idiotic. But I'll make an exception here, because I respect Paul, because he frames an interesting issue in a way I agree with, and because his tweet, which I ultimately disagree with, as I'll explain, is certainly at least partly true, at least from a certain perspective. Paul wrote:

One reason I prefer #scala to #kotlin or #ceylon is it adheres to the #lisp #smalltalk dictum of not confining expressive power to itself.

So, let's start by seeing what's right about this. Where in the language definition does Ceylon "reserve expressive power to itself"?

Well, the things that stand out to me are:

  • control structures,
  • operators,
  • type name abbreviations.

We "reserve expressive power" here, in the sense that we don't let you write your own MyTuple class, and then instantiate it using this syntax:

[String,String] myTuple = ["hello","world"];

If you want to use the brackets, you're stuck with our Tuple class, and if it doesn't suit your needs just right, you're going to have to write:

MyTuple<String,MyTuple<String>> myTuple = MyTuple("hello",MyTuple("world"));

Or whatever. Likewise, while you can certainly use the + operator with your own Complex class, if you want to use it to add a Period to a Datetime, you're out of luck. The Summable<Other> interface expresses that + must be a symmetric operation via the self-type constraint on Other. You're going to have to write:

value date = delay after now;

Or whatever.

Now, I could write a long post defending this choice, but here I'll simply note that:

  • Scala doesn't let you define type abbreviations or control structures either, but
  • it does let you define your own operators.

That is, Scala, like plenty of other languages, lets you take any arbitrary string of unicode characters and turn it into an operator.

And just look at what a mess that turned out to be. Sure, there are some nice uses of operator overloading in the Scala world (parser combinators), along with some abominations (SBT). On balance, I, and many others, believe that untrammeled operator overloading has been a net negative in Scala and C++ and other languages that have tried it. So Ceylon takes a middle road: operator polymorphism.

This means that you're stuck with the operators we think are important. But at least everyone in the Ceylon community is stuck with the same ones! Which makes Ceylon code much more immediately understandable to someone who knows the syntax of Ceylon, because the things which aren't predefined symbolic operators have meaningful names. So if by "expressive power", you take into account the ability to be understood by others, I think of this as a feature.

Fine, anyway, we can agree to disagree on this one, it's not the main point I want to make.

The real point I want to make is that I measure "expressive power" of a language, not mainly by what superficial syntax it supports (though syntax is certainly not unimportant), but rather by what can be expressed within the type system. And here's where it has been a central animating design principle that we weren't going to build in special little escape hatches or ad hoc features for things we think are important. That's why, for example, null is an instance of the ordinary class Null in Ceylon, unlike in Java or Scala where it's a primitively defined value of the bottom type. That's why Tuple is just an ordinary class, and Callable is just an ordinary interface, unlike in many languages where tuple types and function types are defined primitively. That's why the operators we do have are mostly defined to operate against generic interfaces instead of against an enumerated list of language module types.

Now, sure, of course Ceylon could never be compared to Lisp, or even to Smalltalk in this respect. But that's simply an unfair comparison. Of course a dynamically typed language is more expressive than a language with static typing. Duh. You can't reasonably compare the expressiveness of ML or Haskell to Lisp either. But statically typed languages have their own advantages, and that's why static typing is where the real action is right now.

So I think it's a misunderstanding of Ceylon to imagine that we're reserving much expressive power to oursevles. No, we don't let you define your own pope operator (-:|-+>, and I guess some people will find that limits their self-expression. But I believe Ceylon will foster other productive avenues for them to express their creativity.

UPDATE:

To take this argument even further, consider our rule against the use of non-denoteable types: we don't use non-denotable types, or operations upon types that can't be expressed within the language itself, even internally in the typechecker to reason about your code. Since we needed union and intersection types to reason about generics, we needed to make them a part of the language. And they turned out to be perhaps the most interesting and powerful feature of our typesystem.