Fork me on GitHub

Features

Command-Line Compiler

Not an Eclipse fan? Really prefer emacs, vi or TextMate? Want to integrate mobl in your build process?

Have it your way. You can now download a standalone mobl compiler as a single .jar file.

Let us know if you built a code highlighter for mobl syntax in your favorite editor.


Semicolons or no semicolons?

When should I use semicolons (;) and when shouldn’t I in mobl?

It’s a common question. Here’s the reasoning behind requiring semicolons in one context and none in the other.

In mobl, semicolons signify imperative execution, i.e. execution from top to bottom. For instance:

var n = 8;
n = n + 10;
n = n * n;
alert(n);

First create a variable n, and assign 8 to it, then add 10 to n, then multiply n with itself and save the result to n, and then show a pop-up dialog with the result.

A lot of mobl is not imperative but declarative, i.e. you don’t define a recipe of how to get from A to B, but instead you define the desired end-result and let mobl figure out how to realize it. An example of this is mobl’s user interface language:

screen root() {
  header("Welcome")
  group {
    list(t in Task.all()) {
      item { checkBox(t.done, label=t.name) }
    }
  }
}

Ostensibly you may think these are basically just a list of imperative statements. First render a header, then a group, then loop over each item in Task.all(). However, you shouldn’t think of it this way. While this may be the execution order in an initial render, parts of the user interface may react to application state changes later, e.g. when new tasks are added to the Task.all() collection. As a result, the user interface may change a lot after the initial render. In a user interface you define what you want, not how to realize this vision, unlike script where you spell out the steps to a desired result.

To make this conceptual difference clear in the syntax, mobl uses semicolons. Imperative code in mobl uses semicolons, declarative code does not.



Reducing the Pain: Synchronous Asynchronous Programming

Although non-mobile-web-developers may not realize, there is one “feature” of Javascript that causes a lot of pain to Javascript every day — although they may deny it, a case of Stockholm Syndrome, me thinks. That pain point is called asynchronous programming.

Here’s the problem.

Javascript in the browser does not support threads. All the rendering of the page and the Javascript logic that has to be executed shares a single thread. That is OK as long as you do simple things. Simple DOM manipulations, input field validation and so on.

But what if you need to do things that could take a while, say, talk to a database, send an HTTP request to the server — what happens then? In typical synchronous style programming such a HTTP request could look as follows:

var content = fetchURL('http://www.yahoo.com');
processContent(content);

However, fetching the URL could take seconds. Due to the unthreaded nature of this environment, the browser could not do anything during those few seconds because the thread is blocked, resulting in a browser freeze. Bad idea. What can we do about this?

AJAX: Asynchronous Javascript and XML

The idea is to, rather than a blocking, we make a call that returns immediately. When the request finishes, a callback function is called. The request itself is performed on a separate thread (yes, a browser does keep a thread pool for asynchronous actions, but it is not directly accessible for the developer). So, what does that look like?

fetchURLAsync('http://www.yahoo.com',
              function(content) {
  processContent(content);
});

In addition to the regular arguments, an asynchronous function is also passed a callback function, that takes the result of the computation as an argument. The function is called whenever the fetching of the URL has finished, and in the mean time continues executing other code.

Pretty nice solution, right?

It does lead to code that is harder to read, however. In synchronous style programming, we’re used to having code execute from top to bottom. For instance:

var content = fetchURL('http://www.yahoo.com');
processContent(content);
sayHello();

First we fetch the URL, then we process it, then we say hello. Now consider this asynchronous code:

fetchURLAsync('http://www.yahoo.com',
              function(content) {
  processContent(content);
});
sayHello();

Naively this could be read as (top to bottom): first we fetch the URL, then we process the content and then we say hello. However, this is almost certainly not the order in which these statements will be executed. The likely execution order will be: first the url fetch request is sent off, then we say hello and then we process the content.

It gets worse when you try to do loops with asynchronous calls. Let’s say you would like to fetch URLs contained in some array sequentially (one after the other) and then say hello. In the synchronous style you would write the following:

for(var i = 0; i < ar.length; i++) {
  var content = fetchURL(ar[i]);
  processContent(content);
}
sayHello()

Now, how do we do this in an asynchronous style? We may try to do this:

for(var i = 0; i < ar.length; i++) {
  fetchURL(ar[i], function(content) {
    processContent(content);
  });
}
sayHello();

But that’s not going to work. First of all, URLs would now be fetched in parallel (which is kind of cool actually, but not what we wanted) and second, the hello’ing happens too early, not after we’re done with the fetching. What we would need to do is something like this:

ar.reverse(); 

function done() {
   sayHello();
}

function fetchOne() {
  var url = ar.pop();
  fetchURL(ar[i], function(content) {
    processContent(content);
    if(ar.length === 0) {
      done();
    } else {
      fetchOne();
    }
  });
}

if(ar.length === 0) {
  done();
} else {
  fetchOne();
}

Ouch! The idea here is to use the array as a stack. We define a function that processes one URL. The function pops an element off the array, fetches the URL and when done processes it, it checks if the stack is empty, if so, it says hello (done function), if not, it recursively calls itself to process the next element (the new top) in the array.

Luckily, this type of code can be wrapped in a nicer looking API, which allows you to rewrite this code as:

asyncForEach(ar, function(url, callback) {
  fetchURL(ar[i], function(content) {
    processContent(content);
    callback();
  });
}, function() {
  sayHello();
});

But still, wouldn’t you prefer the synchronous version?

Enter mobl

Even though mobl compiles down to Javascript, you do not have to do this style of asynchronous programming. Why? Because the compiler is able to automatically transform synchronous style programs into asynchronous style programs. Yes. Automatically, the compiler does exactly what I just did by hand.

Mobl libraries wrap asynchronous Javascript APIs as synchronous APIs. A simple example. How do you sleep in a Javascript program for 1 second. There’s no sleep function, and even if there would be, it would block the thread and render the browser unusable. If you want something to happen in about 1 second, what you do is you use Javscript’s setTimeout, right?

setTimeout(function() {
  alert('1 second passed!');
}, 1000);

As you can tell, this is another example of an asynchronous call. Here’s what that code looks like in mobl:

sleep(1000);
alert("1 second passed!");

Let’s have a look at the signature of sleep in the mobl standard library:

external function sleep(ms : Num) : void

This signature tells us two things:

  1. There is a function named sleep that takes a single (numeric) argument and returns nothing (void).
  2. This function is asynchronous.

Every external function is assumed to be asynchronous unless stated otherwise (using the sync keyword, e.g. external sync function). Being asynchronous means that in addition to the arguments specified in the signature, a callback function is provided that is to be called when the function completes.

This signature by itself does not do anything, it just tells the mobl compiler that “there exists a function with this name in this module”. The compiler then assumes there’s a definition for it elsewhere, in this case in native Javascript:

<javascript>
__ns.sleep = function(ms, callback) {
  setTimeout(callback, ms);
};
</javascript>

Mobl enables you to include fragments of “native” Javascript in-between <javascript> tags. __ns is a reference to the module’s namespace object. If a function, control or screen is defined in a module it is not put in a global scope, but in a module object named after the module. For instance for the mobl module this object is named mobl, for mobl::ui::generic it’s mobl.ui.generic, a reference to the object can be obtained using the __ns shortcut.

The implementation of sleep takes, as predicted, two arguments: the number of milliseconds to wait, and what to do next (a callback function). It basically delegates this call directly to setTimeout, just switching the argument order.

Alright, so what happens when we call sleep from mobl? What is the Javascript code generated by the following mobl code?

sleep(1000);
alert("1 second passed!");

Cleaned-up a little bit, the resulting Javascript looks as follows:

mobl.sleep(1000, function() {
  mobl.alert("1 second passed!");
});

The transformation performed by the compiler here is called the continuation-passing style transformation, a pretty well-known transformation in academia, although not often applied outside languages like Scheme.

Thanks to the CPS transform, mobl code can be written in a synchronous style, while still maintaining the advantages of asynchronous code, i.e. being non-blocking. One drawback is that writing code that requires concurrent execution — for instance, fetching all the URLs at the same time — is more difficult to express. Mobl does have the async block for this purpose, which conceptually executes its body “on a different thread of execution”, i.e. the code after it can run in parallel with the code inside it:

async {
  sleep(1000);
  alert("I'm last");
}
alert("I'm first!");

Excited? Learn more about mobl.


Copyright © 2010-2011 mobl. All rights reserved.
iDream theme by Templates Next