croczilla.com 
 home   stratified   oni   bits&pieces   blog   personal   
  home > blog > Ubiquity, Oni, and Composability
27 April
2009

Ubiquity, Oni, and Composability

[oni] 

Ubiquity and Composability

One case where the limitations of conventional asynchronous code bubble to the surface is in systems like Ubiquity. E.g. Ubiquity has a 'google' command and a 'translate' command. I can instruct Ubiquity to google for something:
google foo
and I can get Ubiquity to translate something:
translate The quick brown fox to German
but I cannot instruct it to give me list of translated google results:
translate (google foo) to German  // doesn't work
Or email me the resulting list:
email(translate (google foo) to German) // doesn't work
Or email me a list of laptops on ebay below some price:
email(filter(price<500dollars, find_on_ebay(macbook)) // doesn't work
(Ok, excuse the syntax for these examples; in 'real-world' Ubiquity you would probably want this to be in a more natural language style, but I hope I'm getting across the idea of composability. Or rather: lack thereof.)

Oni and Composability

So how does Oni relate to this? Oni is a browser-based "embedded structured concurrency framework". It allows you to write asynchronous code as if it was synchronous, adding back the kind-of composibility that is lost when juggling concurrent strands of execution (such as e.g. pending XMLHttpRequests) with 'conventional' sequential languages.

Oni has recently gained a small AJAX library with some bindings to the Google AJAX APIs. With this new functionality we can write some semi-useful Oni programs which nicely demonstrate the type of composability that Oni provides.

One of the new Oni functions is Google.Feeds.Load(url), which retrieves a JSON object of the RSS feed at 'url'.

With this function it is easy to write an Oni program that e.g. displays the most recent item posted to planet.mozilla.org:

Display(GetMostRecentPost("http://planet.mozilla.org/atom.xml"))
(full sample: composability1.html)

where Display, and GetMostRecentPost are implemented as follows:

var Display = SLift(function(html) { 
                      document.getElementById('output').innerHTML += html; 
                    });
'SLift' is an operator that 'lifts' a conventional sequential JavaScript function into Oni.
var GetMostRecentPost = Defun(['url'], 
                              ObjMem(Google.Feeds.Load(Get('url')),
                                     'entries', 0, 'content'));
'GetMostPost' is a new Oni function which uses 'Google.Feeds.Load' to load the feed, and then traverses the returned feed JSON object using ObjMem, to finally return the html content of the current first post.

So far so good, but this is hardly exciting. Let's add another function into the mix: Google.Language.Translate(text, srclang, destlang), which returns a translation of text (assumed to be in language 'srclang') to language 'destlang'. The object returned by this function is a JSON 'translation result' object of which we only want the 'translation' member, so let's wrap it into a 'Translate' function which extracts just this member:

var Translate = 
  Defun(['txt', 'lang'],
        ObjMem(Google.Language.Translate(Get('txt'), 'en', Get('lang')), 
               'translation'));
Armed with this new function, we can now do something a little more interesting, e.g. retrieve a feed entry and translate it into German:
Display(Translate(GetMostRecentPost("http://planet.mozilla.org/atom.xml"),
                  'de'))
(full sample: composability2.html)

Or retrieve a post and display it in English, German, Spanish and Japanese:

Let({post:GetMostRecentPost("http://planet.mozilla.org/atom.xml")},
    Par(Display(Get('post')),
        Display(Translate(Get('post'), 'de')),
        Display(Translate(Get('post'), 'es')),
        Display(Translate(Get('post'), 'ja'))))
(full sample: composability3.html)

Here, 'Let' introduces a new variable ('post'). 'Par' executes its subexpressions in parallel, so the ordering of what's displayed on screen will depend on the order in which the translation requests return.

Here's another example: Fire off requests to get the most recent post from slashdot and the most recent post from planet mozilla and display a translated version of the first one that comes in:

Display(Translate(Alt(GetMostRecentPost("http://rss.slashdot.org/..."),
                      GetMostRecentPost("http://planet.mozilla.org/...")),
                  'de'))
(full sample: composibility4.html)

Here, 'Alt' is an Oni operator that executes its subexpressions in parallel and returns the first one that returns, at the same time cancelling the other one.

And for a final example, let's add a timeout to the previous example. If we don't get a translation of a planet or slashdot post within 1 second, cancel any pending requests and display a message instead:

Display(Alt(Translate(Alt(GetMostRecentPost("http://rss.slashdot.org/..."),
                          GetMostRecentPost("http://planet.mozilla.org/...")),
                      'de'),
            Delay(1000, "Sites timed out")))
(full sample: composibility5.html)

So what's the big deal?

What these examples illustrate is composability, something that the conventional way of dealing with concurrency lacks. The 'standard' way of coding the examples above would be by using callback functions. This works well enough for simple cases, but as programs become more complex you soon enough end up in 'callback hell'. In Oni (and similar systems such as Orc or Arrowlets), we can build more complex programs out of simpler ones in a modular, structured fashion.

So what's the relationship to Ubiquity? Oni is a low-level framework layered on top of JavaScript. It is not, and does not aspire to be a human interface in the way that Ubiquity is. The relation between the two is only tangential: I believe that Ubiquity could become much more expressive if layered on top of a system like Oni.

If this got you interested, and you'd like to find out more about Oni, please visit the project homepage at http://www.croczilla.com/oni.


Posted by alex at 13:02 | Comments (1)
<< Cross-Browser Oni | Main | Introducing Stratified JavaScript >>
Comments
Re: Ubiquity, Oni, and Composability

very interesting.

Posted by: ray at April 28,2009 11:51