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>
            
            
            
            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.