Pogoscript Notes

Promises

Pogoscript has received some major improvements recently, in the form of promises. All asynchronous features of pogoscript now use promises as the basis for asynchronous semantics, replacing callbacks.

These changes are available in version 0.8 and above. The previous semantics are still available in the 0.7 versions and below. To stick with the old semantics, set "pogo": "~0.7.1" in your package.json.

Skip to the migration cheatsheet below…

Issues with Callback Semantics

The reasons for this are multiple, but also subtle. Pogoscript’s previous asynchronous semantics were brittle in many different situations, especially when dealing with other APIs. And when it didn’t work things got very confusing, no doubt for beginners, but also for hardened pogoscripers. Promises are a much more reliable way to interface with other libraries and offer simpler semantics in regular use too. Beta-users have been quick to migrate to the new semantics and have found them to be a big improvement.

The issues with the old semantics have often be hard to explain (which is most of the problem with broken semantics), but for a good comparison I’ll summarise here:

Previously Pogoscript added an additional callback argument called continuation to the end of functions containing asynchronous calls (those with !). Not only that, but it would actively search for the last not-undefined argument, and if it was a function, use that as the continuation. (This allowed for passing variable numbers of arguments to async functions.) But these assumptions resulted in problems in some popular frameworks:

  1. In AngularJS, people would receive a Unknown provider: continuationProvider <- continuation error. If one of your controllers contained a !, Angular’s dependency injection system would try to resolve the continuation parameter, giving this bizarre message. To work around it, programmers would put the asynchronous calls inside a block to another non-async function.

  2. Express and connect define a calling signature for HTTP handlers: function (request, response, next) {...}, the last parameter is a next function that you can call to pass the request on to the next handler, to essentially delegate the request upstream. The problem with the next argument was that it was a function, and Pogoscript would confuse it with the continuation callback function, and would call next when any asynchronous code had finished in the handler. This was fairly disasterous, as handlers were deferring request handling even when they’d finished responding to the request. Again, the solution was to write a shim function that bridged the calling conventions.

Understanding how to write these shim functions wasn’t always that easy, and while only a small part of any serious Pogoscript project, they weren’t something I was particularly proud of.

There were other issues too. Given a function f, one was never sure whether it should be called asynchronously with the ! or not. This wasn’t a huge problem, but turned up occasionally when writing libraries that could, in theory at least, work with both regular synchronous and asynchronous clients. As we’ll see with promises, it’s enough just to call it and check if the result is a promise or not.

Promises Semantics

The semantics themselves aren’t a huge departure from those found in previous versions. Most pogoscript code “just works”, although, in any given program, especially code that interacts with other libraries, there will be significant differences. On the whole, most Pogoscript code won’t need to change.

Let’s go through the new semantics first, then we’ll compare with the old.

Asynchronous functions in pogoscript now return promises. These promises are Promises/A+ compliant and in fact by default pogoscript generated code uses a popular promises library called bluebird.

Now let’s imagine we have an an asynchronous function userDetailsFor(user). One can call it, userDetailsFor 'bob' and it will return a promise, which can be resolved into Bob’s user details. If you want to wait for the promise to resolve and return it’s value immediately, then we can call it with the ! operator, as in: userDetailsFor 'bob'!. The ! operator can be used to resolve a promise, either when calling a function that returns a promise, or just to resolve a promise on its own.

So this:

bobsDetails = userDetailsFor 'bob'!

Is the same as:

p = userDetailsFor 'bob'
bobsDetails = p!

The last line above highlights a slight syntactical difference with previous versions of pogoscript: p! in the old version was equivalent to, and even shorthand for p()!. In the new version, these two are different, p! resolves the promise p, while p()! calls the function p and resolves its result.

Futures in the old pogoscript have been dropped since all asynchronous functions now return promises, which are functionally equivalent, if not quite exactly semantically equivalent to futures.

The rest of Pogoscript follows original semantics: list comprehensions are executed concurrently, while for, for each, if else and while control structures are executed in serial, blocking fashion.

Interfacing with callback-style functions

The largest change is in interfacing with other libraries. Since the underlying asynchronous mechanism is now promises and not callbacks, we have to call callback-style functions differently. We use the ^ operator to mark the callback argument, and the result is a promise which we can resolve with !. For example, to make calls to the Node.js fs.readFile function, we would use ^ in place of the callback and then ! to resolve the promise:

fs = require 'fs'
content = fs.readFile 'filename.txt' 'utf-8' ^!

The ^ operator, now being explicit about the location of the callback, can be used with setTimeout too:

setTimeout ^ 1000!
console.log "after a 1 second wait"

Explicit returns and errors

There are of course other integrations that are more complicated, and require more explicit ways of notifying when an operation is actually complete. Previously we called the continuation function explicitly when either an error occurred or a successful result was known. Now we have a promise keyword, that takes a block with two arguments, success and failure. You can still make asynchronous calls inside the block, but it won’t be “finished” until one of these functions are called.

A common integration is jQuery’s AJAX functions, lets start with the simple $.get:

get (path) =
  promise @(success, failure)
    $.get '/data'.done (success).fail (failure)

Or to illustrate:

promise @(success)
  setTimeout @{ success 'result' } 1000

Calling success with an argument returns the result of the promise.

Otherwise:

promise @(success, failure)
  setTimeout @{ failure 'uh oh' } 1000

Calling failure fails the promise, throwing an exception which would be handled by pogoscript’s try catch finally construct as normal.

promise is useful for these types of things, but you have to remember that unlike regular asynchronous functions, inside promise block, you must call either success or failure or the promise will not return.

Promise APIs

Of course, if an API returns promises then you have nothing to do, just call those functions with the ! and results will be resolved.

Calling Pogoscript from Javascript

The other biggish difference is in any regular Javascript code you may have interfacing with Pogoscript code. Pogo now returns promises instead of accepting callbacks to asynchronous functions. So if you had code that looked like this:

pogoFunction(x, y, function (error, result) {
  if (error) {
    handleError(error);
  } else {
    handleResult(result);
  }
});

Then you’d want to transform it into this:

pogoFunction(x, y).then(function (result) {
  handleResult(result);
}, function (error) {
  handleError(error);
});

Notice also that promises are returned as results, which is different from results being passed to callback functions. If you have this:

function myFunction(x, y, callback) {
  pogoFunction(x, y, callback);
}

Then you’d want to transform it into:

function myFunction(x, y) {
  return pogoFunction(x, y);
}

Promises Library

The default promises library at the moment is bluebird. If you want to change this, the command line takes a -p|--promises argument, which is the name of a promises module in your require path. The module is expected to return the Promise constructor itself, as in:

var Promise = require('my-promises-library');
new Promise (function (onSuccess, onFailure) { ... });

If you don’t want to use a Promises library, say for example you want to use the native Promises of Chrome, or you’re using a ES6 Promises shim, then you can set --promises none and generated Pogoscript code will assume window.Promise exists.

Migration Cheatsheet

For internal Pogoscript code:

f(x)! => f(x)! (no change).

f! => f()!

f(x)? => f(x)

f? => f()

For external callback-style libraries (Node.js):

f(x)! => f(x, ^)!

For explicit returns and errors:

f(x)! =
  ...
    continuation (nil, 'result')
  ...
    continuation ('error')

becomes

f(x)! =
  promise @(success, failure)
    ...
      success ('result')
    ...
      failure ('error')
comments powered by Disqus