Archive

Archive for October, 2012

A way that async/await-style functionality might make it into browsers

October 9, 2012 1 comment

Many moons ago (actually it’s 35.7 moons ago) I wrote an excited post about JavaScript generators in Firefox. Sadly they are still only in Firefox, and there’s no sign of them appearing elsewhere.

But one way they could appear elsewhere is via compilers that generate plain JavaScript, and the latest player is TypeScript. Why is this a good fit? Because, with a very thin layer of helper code, generators replicate the functionality of C# 5’s async/await, and if that was a good idea for C# and Silverlight, it’s got to be a good idea for TypeScript. (The downside is that the auto-generated JavaScript would not be very readable, but I can still dream that this will happen…)

My old post is somewhat messy because I was unaware of jQuery.Deferred. If we bring that into the mix, to serve as the JS equivalent of Task, then things get really nice. To wit:

async(function() {
  
  // sleeping inside a loop
  for (var n = 0; n < 10; n++) {
    $('.counter').text('Counting: ' + n);
    yield sleep(500);
  }

  // asynchronous download
  $('.downloaded').text(yield $.get('test.txt'));

  // and some more looping, why not
  for (var n = 0; n < 10; n++) {
    $('.counter').text('Counting: ' + (10 - n));
    yield sleep(500);
  }
});

In other words, by passing a function to something called async, I can use the yield keyword in exactly the same way as C# 5’s await keyword.

The yielded values are just jquery.Deferred objects – or rather, they are objects that contain a function called done, to which a resulting value may be passed (at some later time). So the implementation of sleep is straightforward:

var sleep = function(ms) {
  var d = $.Deferred();
  setTimeout(function() { d.resolve(); }, ms);
  return d;
};

By calling resolve, we trigger any registered done functions. So who is registering? This is what async looks like:

var async = function(gen) {
  var result;
  var step = function() {
    var yielded;

    try {
      yielded = gen.send(result); // run to next yield
    } catch (x) {
      if (x instanceof StopIteration) {
        return;
      }
      throw x;
    }

    yielded.done(function(newResult) {
      result = newResult; // what to return from yield
      step();
    });
  };
  gen = gen(); // start the generator
  step();
};

So async calls the function passed to it to get a generator object. It can then repeatedly call send on that object to pass it values (which will be returned from yield inside the generator). It assumes that the objects that come back from send (which were passed to yield inside the generator) will have a done function, allowing us to register to be notified when an asynchronous operation completes.

Note that async could use some further complication, because it currently doesn’t deal with exceptions (note that the try/catch block above is merely to deal with the strange way that generators indicate when they’ve finished). But generators have full support for communicating exceptions back to the yielding code, so it should all be do-able.

And that’s all there is to it. You can see the example running here:

http://earwicker.com/yieldasync/

… but only in Firefox, of course.

Categories: Uncategorized Tags: , ,

TypeScript reactions

October 5, 2012 Leave a comment

Miscellaneous

Great implementation of modules. I use commonjs on the browser side (yes, the non-asynchronous module pattern), so the default suits me fine.

Love the => syntax of course, and the fact that it fixes the meaning of this within lambdas. No need to manually copy into a that variable.

Type system

… appears to be better than that of C#/CLR. Structural typing is clearly the right way to do it. It makes much more sense than nominal typing. The dumbest example of that in C# is the strange fact that two identically-signatured delegate types are not assignment compatible. Well, in TS, types are compared by their structures, not their names, so that problem goes away. And the same for classes and interfaces. If a class could implement an interface, then it already does. When they add generics, it’s going to be excellent.

I wonder if they’ve given any thought to the problem of evolution of interfaces. Default implementations of methods (this could be implemented by having the compiler insert some checking/substitution code at the call site).

Async, await, async, await, async, await…

The really big missing ingredient is continuations. They’ve just added this to C#. Clearly it is just as important for browser-based apps, if not more important. And consider the fact that server-side JS at the moment is roughly synonymous with node, which is crying out for continuations in the language. From a Twitter conversation with Joe Palmer, it’s clear that the TS team currently places a big emphasis on the clean appearance of the JS output. But I think they’re going to have to twist the arms of the IE teams and get source map support working, and then they can butcher the JS as much as they like without hurting the debugging experience.

The Dreaded C++ Comparison

Theses days a C++ comparison from me is normally an insult (despite speaking ASFAC++B) but in this case, definitely not. C++ beat a lot of other languages simply by inheriting C. And JS is the C of the web, so TS has a good chance of being the C++ of the web, in the sense of becoming equally popular as its parent language, while probably not actually displacing it everywhere.

And at its best, C++ was a collection of extensions to C, a pretty ugly platform to start building on. To do that tastefully was a challenge, and (despite what people say in jest) C++ succeeded in lots of ways. Playing with TS, I see a similarly tastefully chosen set of extensions.

When you consider C++0x concepts, which were going to be (and may yet one day be) structural type definitions layered over the existing duck-typing of C++ templates, the comparison becomes even stronger. TS’s type system has a lot in common with C++0x concepts.

The Competition

A common criticism so far seems to be “Why not use (my favourite language X) as a starting point?” The answer, surely, is that it may be your favourite language but it’s nowhere compared to JS, which is now so widely deployed and used that it makes most other languages look like hobby projects! This criticism is correlated strongly with the idea that JS is a toy language, disgusting, revolting, etc., i.e. irrational emotional garbage. JS has a lot of stupid things in it, yes, we all know about {} + {} and [] + [] and {} + [] and so on, but I’ve now churned out a zillion lines of JS without ever hitting such issues. No language is perfect, but is JS useful? Yes.

In fact, the main competition faced by TS is therefore JS. This is why I think TS needs to do some heavy lifting (such as continuation support) besides a mere layer of sugar and type checking, in order to become a compelling advantage over JS itself.

And then there is CoffeeScript. Syntax just isn’t that important for most people. Semantics are much more important. It’s no good that your code looks really short and pretty if it takes you just as long to figure out what it needs to say. By the addition of static typing, TS holds out the hope of genuinely improving productivity. (With continuations it could asynchronous event-driven programming a lot easier too.)

Oh and there’s Dart. I can’t even begin to understand what Google is thinking. It’s not compatible with, nor discernibly superior in any way, to anything that already exists. It’s just their version of the same old stuff.