Transform js-style callback to Future with Haxe macro

EDIT (4 July 2016): A newer solution for this problem can be found at: https://github.com/kevinresol/futurize

Haxe macro is very powerful and it is really good at eliminating boiler-plate codes.

In the past 2 months I have been working on a web server using haxe/nodejs + ufront + mongoose (through js-kit). Since ufront supports async operations through Futures while mongoose uses js-style function callbacks, I have to write a lot of bolier-plate codes to convert the latter to the former, like this:

However, it is very cumbersome. If I have more than 100 database call like that, I have to write that code 100 times. So I decided to wrap it up in some functions at the very beginning. At first I tried using abstract to wrap each mongoose function and return a future, like this:

But it turns out quickly that it is creating more problems than solving any:

  • I have to create a function for each mongoose function I am going to use.
  • Wrapping mongoose’s chained methods like Model.where('field', value).count(callback) is even more cumbersome.
  • What’s worse is that with abstract I have no way to declare method overload, which is very common in js libaries.

At the end, macro came in and rescued me. Now I can write my code in just one line, while still supporting every mongoose features:

Here is the source code of the macro:
[Edited: Thanks for Jason’s advice that my original code (see below) can be simplified a lot with the help of the tink_macro library]

Here is the source code of the macro before Jason’s comment:

4 thoughts on “Transform js-style callback to Future with Haxe macro

  1. Also because of the method chaining in mongoose, this may not be helpful, but AsyncTools was supposed to help in these situations. See http://api.ufront.net/ufront/core/CallbackTools.html

    using ufront.core.AsyncTools;
    
    var findFuture = myModelManager.find.bind({}).asSurprise(); 
    var updateFuture = myModelManager.update.bind({}, {data:data}).asSurprise(); 
    var countFuture = myModelManager.where('field', value).count.asSurprise(); 
    var removeFuture = myModelManager.remove.bind({}).asVoidSurprise();
    

    I wonder if there’s a macro we could use to combine the best of your approach with this approach?

Leave a Reply

Your email address will not be published. Required fields are marked *