Skip to content

add a macro to ease the use node.js callbacks? #56

@darrencruse

Description

@darrencruse

Was just playing with a little example of walking file directories asyncronously with node.js and it struck me lispyscript might be well positioned to simplify/hide/eliminate the use of callbacks...

I actually tried it out with a little macro and was delighted with how easy lispyscript made it (i'd been playing with generators recently and this was remarkably simple by comparison!!).

Here's my original function in lispyscript using callbacks:

(var fs (require 'fs'))

(function walk (rootDir)
  (fs.readdir rootDir (function (err files)
    (each files (function (file)
      (do
        (var filePath (str rootDir '/' file))
        (fs.stat filePath (function (err stats)
          (if (stats.isDirectory)
            (do
              (console.log 'directory:' filePath)
              (walk filePath))
            (console.log filePath))))))))))

(walk '.')

Here's the same code with a little "await" macro (which I show further down):

(var fs (require 'fs'))

(function walk (rootDir)
  (await files (fs.readdir rootDir)
    (each files (function (file)
      (var filePath (str rootDir '/' file))
      (await stats (fs.stat filePath)
        (if (stats.isDirectory)
          (do
            (console.log 'directory:' filePath)
              (walk filePath))
          (console.log filePath)))))))

(walk '.')

And here's the little "await" macro:

(macro await (result asynccall rest...)
  (~@asynccall (function (err ~result)
    ~rest...)))

As I mentioned above - I was delighted the above macro was so short and actually worked perfectly on the first try!!

I was trying to think if the same macro could work with both callback taking functions and promise-returning functions without the programmer having to use a different macro.

I couldn't think of any way - please others comment if somebody sees a way.

As it is I could easily see their being an "awaitp" for "await promise" as a sister to the above?

Also I obviously have ignored errors in the above I need to correct that. I thought I would have the macro include code to throw the received "err" parameter if it gets one.

    edit:  I had a feeling I was going to look like an idiot for writing the above...
I know exception handling is broken with async callbacks but I keep having 
selective memory wanting it not to be true...  I guess the "handle the err yourself" 
option below should really should be the only option where node callbacks are used(?)  
But something nicer could/should be done where promises or generators are involved.  
Nice article about such things fwiw:  
    https://strongloop.com/strongblog/comparing-node-js-promises-trycatch-zone-js-angular/

But maybe there should be a way to handle the err parameter yourself if you want to... The ideal syntax to me would look like destructuring assignment:

So this if you want to handle the err yourself:

  (await (err files) (fs.readdir rootDir) 

This if you want it to throw if there's an error:

  (await files (fs.readdir rootDir) 

Would that be doable I wonder?

(still learning the finer points of macros - seems to me the above implies in my macro I need some logic distinguishing what form I've gotten as the first "result" argument to the macro. I don't know how to do that ATM).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions