I’m working on an experimental programming language called Sodium. Although I haven’t introduced the language yet, I must share a wonderful idea that recently occurred to me. These examples are written in Sodium, but I’ve avoided some unusual idioms; hopefully they will make sense to anyone with some programming background.
If I do a CPS transform, I can easily do exception-passing with
continuations, exactly like return values. Every expression will have two
continuations: success and failure (corresponding to
raise). This implies
call-with-current-continuations, plural. And
that means I can write the following mind-blowing function:
def (wormhole promise): call/ccs (fn (success failure) (promise.on-success success) (promise.on-failure failure) (escape.))
escape is just another continuation, saved at the beginning of the
process, that pops back out to the main event loop.)
wormhole do? Consider the following snippet of typical
asynchronous I/O code:
site = "example.net" path = "/robots.txt" promise = (http.get site path) promise.on-success (fn (robots-txt) (spider site robots-txt)) promise.on-failure (fn (error) (spider-all site))
This sort of thing can get pretty deeply nested and ugly, especially if you need to use lots of local variables.
wormhole, you can rewrite it:
site = "example.net" path = "/robots.txt" try: robots-txt = (wormhole (http.get site path)) spider site robots-txt catch error: spider-all site
This new example is fully asynchronous, just like the first one, but it is much more readable (as long as you know what’s really going on under the hood).
The wormhole operator has pretty serious implications for any callers of your code who expect things to happen in the usual synchronous order. It’s not clear if the resulting code is really any better, on balance.
Certainly, anyone tempted to use this device should think hard first. At least until we understand it better and develop rules of thumb. I think this function should be discouraged for library code, but, in the right circumstances, it might do for top-level application code. The end result can be simple and pretty while still fully asynchronous.