async/await -> await/async: a simpler, less error-prone async syntax

Steven Mascaro subs at voracity.org
Mon Dec 4 13:09:03 UTC 2017


Oh, and just to be clear, there would still need to be an explanation for
why you need to attach `async` or `await` to any function that contains a
call to an asynchronous function. I assume that requirement exists for
performance reasons --- I have suggested that requirement be dropped
elsewhere, but understand that may not be practical.

On 4 December 2017 at 23:52, Steven Mascaro <subs at voracity.org> wrote:

> 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.
>
> Cheers,
> Steven
>
>
> On 4 December 2017 at 16:38, Naveen Chawla <naveen.chwl at gmail.com> wrote:
>
>> The crux of your idea is: let any calls of an async function inside an
>> async function automatically await unless explicity instructed to run "in
>> the background". I like the idea. I just wouldn't use the words "await" and
>> "async" for it, because they are used as currently in C#.
>>
>> On the last disagreement by T.J Crowder: 1. it's an alternative (perhaps
>> with different words), not necessarily in conjunction with the existing
>> syntax. 2. The promise would be accessible via e.g. `const promise = background
>> remote.runInBackground();` 3. If a presumption is made that in an async
>> function, other async function calls are automatically awaited unless
>> prefixed with `background`, I'm not sure about the value of having a "clear
>> indicator" of which function calls are sync and which are async - in normal
>> use I wouldn't care. I just want their results and if I want to make a
>> function async (by adding a server call, etc.), I can do so transparently
>> without breaking my code. I agree with the thrust of this proposal.
>>
>> The horse has bolted on `await` `async`, but maybe with different
>> keywords, e.g. `asyncauto` and `background`, I would definitely use this
>> new syntax instead of `await` `async` (which I use currently), for the
>> reasons stated in the original post. Bug minimization is a big factor in
>> the features I use, and should be THE driving factor in introducing new
>> features.
>>
>> The OP has stated this idea upon extensive real world use, and I
>> appreciate that. I would definitely support the introduction of e.g.
>> `asyncauto` and `background`, and would definitely use it immediately in
>> all cases instead of `async` `await` if introduced.
>>
>> On Sun, 3 Dec 2017 at 17:13 T.J. Crowder <tj.crowder at farsightsoftware.com>
>> wrote:
>>
>>> I understand the motivation, but I have to disagree with the proposal
>>> for multiple reasons:
>>>
>>> 1. It adds too much confusion to the existing syntax.
>>>
>>> 2. If the calling code needs to call one of these new-style `await`
>>> functions and access its promise (rather than `await`ing it), it
>>> doesn't have a way to do that; `async`/`await` doesn't have full
>>> coverage of all patterns (yet, possibly never), sometimes you still
>>> need to access the actual promise (for instance, to feed into
>>> `Promise.all` or `Promise.race`). (Obviously you could add something
>>> to make it possible to access the promise.)
>>>
>>> 3. Having a clear indicator in the source saying where the async
>>> boundaries are is useful for code correctness. With the new syntax, I
>>> have no idea of the temporal sequence of this code:
>>>
>>> ```js
>>> let x = foo();
>>> let y = bar();
>>> ```
>>>
>>> ...without going and looking at the declarations of `foo` and `bar`.
>>> With current syntax, it's clear when there's an async break in the
>>> flow. I think the phrase is "prefer explicit to implicit" or something
>>> like that.
>>>
>>> -- T.J. Crowder
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20171205/d069efe8/attachment-0001.html>


More information about the es-discuss mailing list