Steven Mascaro (2017-12-04T12:52:48.000Z)
subs at voracity.org (2017-12-04T13:12:59.747Z)
Thanks Naveen, I agree, potentially in full. Let me address T.J. Crowder's objections out of order (2,3,1), as the response will be clearer that way. 2. As Naveen noted, this is a use case that I did (and very much intended to) handle in the proposal by having a keyword at the call site. Namely: `let promise = async remote.runInBackground();`. 3. I think the principle "prefer explicit to implicit" argues in *favour* of the proposal (and against the existing syntax). You gave the example: ```js let x = foo(); let y = bar(); ``` Imperative language conventions imply the second statement only executes after the first is fully complete. But if `foo` and `bar` are defined as async functions, the second statement likely starts executing before the *real* work being done in the first statement is complete. The proposed syntax restores the normal imperative conventions, and requires one to be explicit when code departs from those conventions. e.g.: ```js let p = async baz(); // We're explicit that this doesn't work like every //other sync function, it just returns a promise! let x = foo(); // This could be an await function or an ordinary sync // function. We don't need to care (outside of // atomics,etc.) let y = bar(x); // Ditto ``` If you're really committed to being explicit, then we should require the coder to specify how they want *every* call to an async function to be handled. e.g.: ```js let p = async baz(); // Explicit let x = await foo(); // Explicit let y = await bar(x); // Explicit ``` But this seems needlessly verbose. 1. I'm not committed to keeping the `async` and `await` keywords. My original thoughts on this were much like Naveen's proposed keywords. I was initially using `awaitalways` for `await` in the function declaration and `trap` for `async` at the call site, but if we do want to use different keywords, I think I prefer `awaitauto` and `background`. (`awaitauto` rather than `asyncauto` because I think it's very important to be clear about what the default call behaviour becomes.) However, I later realised that the keyword reuse will only be confusing to someone who has only learned the existing (essentially incomplete) async/await syntax. Someone entirely *new* to the language may actually find the completed symmetry of the proposal *less* confusing. The explanation for a new JS developer might run as follows: --- Asynchronous Functions === An "asynchronous function" is any function that returns a `Promise`. `async` and `await` control how an asynchronous function is executed. Prefixing a call to an asynchronous function with `async` will cause it to be run in an asynchronous thread, and will return the `Promise`. Prefixing a function call with `await` will cause execution of the current function to be suspended until the asynchronous function has completed (successfully or otherwise), potentially returning a value computed by the function. Specifying how asynchronous functions should be called every time is cumbersome and error-prone, so you can specify the default approach to calling the function in the function declaration. Thus: ```js async function foo() {} ``` specifies that all calls to the function `foo` will use the `async` method by default and ```js await function bar() {} ``` specifies that all calls to the function `bar` will use the `await` method by default. In either case, you can override the default and force the call behaviour by prefixing the call with either `await` or `async`. --- And I think this possibly makes things far clearer than any description I've yet seen, not because it was especially eloquent, but simply because the missing pieces have now been filled in. Nonetheless, I could be convinced otherwise, and I'd be more than willing to accept Naveen's suggestions for different keywords.
subs at voracity.org (2017-12-04T13:01:30.705Z)
Thanks Naveen, I agree, potentially in full. Let me address T.J. Crowder's objections out of order (2,3,1), as the response will be clearer that way. 2. As Naveen noted, this is a use case that I did (and very much intended to) handle in the proposal by having a keyword at the call site. Namely: `let promise = async remote.runInBackground();`. 3. I think the principle "prefer explicit to implicit" argues in *favour* of the proposal (and against the existing syntax). You gave the example: ```js let x = foo(); let y = bar(); ``` Imperative language conventions imply the second statement only executes after the first is fully complete. But if `foo` and `bar` are defined as async functions, the second statement likely starts executing before the *real* work being done in the first statement is complete. The proposed syntax restores the normal imperative conventions, and requires one to be explicit when code departs from those conventions. e.g.: ```js let p = async baz(); // We're explicit that this doesn't work like every other sync function, it just returns a promise! let x = foo(); // This could be an await function or an ordinary sync function. We don't need to care (outside of atomics,etc.) let y = bar(x); // Ditto ``` If you're really committed to being explicit, then we should require the coder to specify how they want *every* call to an async function to be handled. e.g.: ```js let p = async baz(); // Explicit let x = await foo(); // Explicit let y = await bar(x); // Explicit ``` But this seems needlessly verbose. 1. I'm not committed to keeping the `async` and `await` keywords. My original thoughts on this were much like Naveen's proposed keywords. I was initially using `awaitalways` for `await` in the function declaration and `trap` for `async` at the call site, but if we do want to use different keywords, I think I prefer `awaitauto` and `background`. (`awaitauto` rather than `asyncauto` because I think it's very important to be clear about what the default call behaviour becomes.) However, I later realised that the keyword reuse will only be confusing to someone who has only learned the existing (essentially incomplete) async/await syntax. Someone entirely *new* to the language may actually find the completed symmetry of the proposal *less* confusing. The explanation for a new JS developer might run as follows: --- Asynchronous Functions === An "asynchronous function" is any function that returns a `Promise`. `async` and `await` control how an asynchronous function is executed. Prefixing a call to an asynchronous function with `async` will cause it to be run in an asynchronous thread, and will return the `Promise`. Prefixing a function call with `await` will cause execution of the current function to be suspended until the asynchronous function has completed (successfully or otherwise), potentially returning a value computed by the function. Specifying how asynchronous functions should be called every time is cumbersome and error-prone, so you can specify the default approach to calling the function in the function declaration. Thus: ```js async function foo() {} ``` specifies that all calls to the function `foo` will use the `async` method by default and ```js await function bar() {} ``` specifies that all calls to the function `bar` will use the `await` method by default. In either case, you can override the default and force the call behaviour by prefixing the call with either `await` or `async`. --- And I think this possibly makes things far clearer than any description I've yet seen, not because it was especially eloquent, but simply because the missing pieces have now been filled in. Nonetheless, I could be convinced otherwise, and I'd be more than willing to accept Naveen's suggestions for different keywords.
subs at voracity.org (2017-12-04T12:59:12.589Z)
Thanks Naveen, I agree, potentially in full. Let me address T.J. Crowder's objections out of order (2,3,1), as the response will be clearer that way. 2. As Naveen noted, this is a use case that I did (and very much intended to) handle in the proposal by having a keyword at the call site. Namely: `let promise = async remote.runInBackground();`. 3. I think the principle "prefer explicit to implicit" argues in *favour* of the proposal (and against the existing syntax). You gave the example: ```js let x = foo(); let y = bar(); ``` Imperative language conventions imply the second statement only executes after the first is fully complete. But if `foo` and `bar` are defined as async functions, the second statement likely starts executing before the *real* work being done in the first statement is complete. The proposed syntax restores the normal imperative conventions, and requires one to be explicit when code departs from those conventions. e.g.: ```js let p = async baz(); // We're explicit that this doesn't work like every other sync function, it just returns a promise! let x = foo(); // This could be an await function or an ordinary sync function. We don't need to care (outside of atomics,etc.) let y = bar(x); // Ditto ``` If you're really committed to being explicit, then we should require the coder to specify how they want *every* call to an async function to be handled. e.g.: ```js let p = async baz(); // Explicit let x = await foo(); // Explicit let y = await bar(x); // Explicit ``` But this seems needlessly verbose. 1. I'm not committed to keeping the `async` and `await` keywords. My original thoughts on this were much like Naveen's proposed keywords. I was initially using `awaitalways` for `await` in the function declaration and `trap` for `async` at the call site, but if we do want to use different keywords, I think I prefer `awaitauto` and `background`. (`awaitauto` rather than `asyncauto` because I think it's very important to be clear about what the default call behaviour becomes.) However, I later realised that the keyword reuse will only be confusing to someone who has only learned the existing (essentially incomplete) async/await syntax. Someone entirely *new* to the language may actually find the completed symmetry of the proposal *less* confusing. The explanation for a new JS developer might run as follows: *Asynchronous Functions* An "asynchronous function" is any function that returns a `Promise`. `async` and `await` control how an asynchronous function is executed. Prefixing a call to an asynchronous function with `async` will cause it to be run in an asynchronous thread, and will return the `Promise`. Prefixing a function call with `await` will cause execution of the current function to be suspended until the asynchronous function has completed (successfully or otherwise), potentially returning a value computed by the function. Specifying how asynchronous functions should be called every time is cumbersome and error-prone, so you can specify the default approach to calling the function in the function declaration. Thus: ```js async function foo() {} ``` specifies that all calls to the function `foo` will use the `async` method by default and ```js await function bar() {} ``` specifies that all calls to the function `bar` will use the `await` method by default. In either case, you can override the default and force the call behaviour by prefixing the call with either `await` or `async`. And I think this possibly makes things far clearer than any description I've yet seen, not because it was especially eloquent, but simply because the missing pieces have now been filled in. Nonetheless, I could be convinced otherwise, and I'd be more than willing to accept Naveen's suggestions for different keywords.