samuelgoto / proposal-block-params

A syntactical simplification in JS to enable DSLs
204 stars 8 forks source link

What happens with await inside a block param? #28

Open samuelgoto opened 6 years ago

samuelgoto commented 6 years ago

@dherman writes:

async function readstuff (cfg) {
  let fileA = null;
  unless (cfg.skipA) {
    fileA = await cfg.fileA;
  }
  // ...
}

Are await allowed inside block params? If so, do they interrupt the execution of readstuff or unless?

dherman commented 6 years ago

Thanks for capturing this, Sam! (BTW it's missing an async on the function declaration.) My reason for writing it up is that I think this is one of the trickier technical issues here, and I think it's really important. If people learn that control structures can't be used reliably because they break inside async functions, they'll just take away that control structures built with block params are unreliable.

(Basically in a bake-off between async functions and block params, async functions will win.)

dherman commented 6 years ago

But I should also add that I think Ron's ideas on the call were promising -- maybe there are solutions involving protocols like the iterator protocol, where we could actually allow propagation of await (and similarly yield).

In general, I'm saying that we should aim to get as absolutely close to TCP as possible, or else risk the feature being too non-general and unreliable to succeed. But I think there's reason for optimism that that's solvable!

dissimulate commented 6 years ago

I think it'd be unintuitive to have any behaviour other than interrupting both, looking at that code it's how I'd expect it to run. Disallowing await inside the block is an option I suppose, but I think that's a feature people would certainly find useful as per your example.

There's more to think about though:

async function one (cb) {
  const result = await thing();
  cb();
}

function two (cb) {
  cb();
}

async function three () {
  // blocks until the callback it called
  await one () {
    // you can now block three() here
    await thing();
  }

  // what happens now? you'd expect the block to execute asynchronously
  one () {
    // ...but then the above behaviour won't work here
    await thing();
  }

  two () {
    // ...and it does here
    await thing();
  }

  // this shouldn't execute until all three thing()'s are complete
  const result = await thing();
  return result;
}

three();

Perhaps functions have an implicit await when called in the block param format, the behaviour will be consistent and this code would run as expected.

Sceat commented 5 years ago

let's totally break javascript for the sake of sexyness

// base
one(async x => {
    await x
})

// block params
one async {
    ::await
}