maxtaco / coffee-script

IcedCoffeeScript
http://maxtaco.github.com/coffee-script
MIT License
727 stars 58 forks source link

Optionally include defer arguments after await #134

Open m1sta opened 9 years ago

m1sta commented 9 years ago

Just throwing up an idea. This is completely half baked. How about supporting the following syntax...

on (err) return error(err)
await (err, data) = http.post(data, url, defer)
await (err, data) as result and (bla) as special = db.get(key, result, special)
await (err, data) as result or (bla) as special = db.get(key, result, special)
  1. Allowing the callback paramers to be placed immediatley after await is more readable imho.
  2. Use of the as keyword to manage when one function accepts two callbacks
  3. The on keyword would record an expression to be evaluated just before any await callback is fired.
malgorithms commented 9 years ago

I think there would be a couple issues here. Most notably that there's a disconnect between the await wrapper and the number of defers. You can do pretty funky things:

await
   foo defer(err1, res1)
   foo defer(err2, res2)
   if bar?
     foo defer(err3, res3)
  some_process_queue_class_i_wrote.add defer()

I feel this is pretty readable but some front-loaded system of these conditional defers would be pretty hard to write.

If I understand it correctly, your syntax change works only on awaits that have single defers inside them. (Or am I misreading?)

The error handling is interesting, although I don't think a "return" would be possible because whatever function you're talking about is an async function, and this is happening after awaited callbacks. A very similar and awesome solution is max's "error short circuiter" class, which is super simple and powerful:

http://maxtaco.github.io/programming/2014/09/18/handling-errors-in-iced-coffee-script/

# this handles the error for you and short-circuits your cb with the error if there is one:
await http.post data, url, esc defer data
m1sta commented 9 years ago

I'm thinking more of sequential scenarios, but I'd imagine your example might become...

await
    (err1, result1) = foo defer
    (err2, result2) = foo defer
    if bar? then (err3, result3) = foo defer
 some_process_queue_class_i_wrote.add defer

or, with splats indicating that a callback argument should be pushed to an array of the given name, ...

await
    (errors..., result1) = foo defer
    (errors..., result2) = foo defer
    if bar? then (err3, result3) = foo defer
if errors.length then error("An error occured")
else some_process_queue_class_i_wrote.add defer

or, maybe

on errors then error("An error occured", errors) 
await (errors..., results...) as resultCollector
    foo resultCollector
    foo resultCollector
    if bar? foo resultCollector

if !errors then await (finalAnswer) = some_process_queue_class_i_wrote.add results, defer

I like the first one the best. Note that I'm assuming a change so that defer can be used as a keyword/statement instead of as a faux function.