Re: Stage 0 proposal: specifying concurrency for "for...of" loops potentially containing "await" statements

2019-09-07 Thread Cyril Auburtin
It should really be in the form of a  static method like `Promise.map` or
some other naming

On Sat, Sep 7, 2019 at 6:40 PM Tom Boutell  wrote:

> Up to five instances of the loop body would be in progress, assuming at
> least one of them awaits at some point. any await inside the loop body
> would be respected with regard to code that follows it in the loop body.
> The only place concurrency comes into play is that more than one of these
> loopbodies could be in progress for separate items, for instance they could
> all be awaiting  a long database operation or API call. To avoid the
> frequent problems that come up with unlimited concurrency when dealing with
> apis and similar, you set the concurrency so that you don't exceed those
> reasonable limits.
>
> On Sat, Sep 7, 2019, 12:24 PM Bob Myers  wrote:
>
>> I don't understand how this would work.
>>
>> ```
>> for (const thing of things concurrency 5) {
>>   const result = await thing();
>>   console.log(result); // <== what is `result` here, if the call to
>> thing() hasn't completed?
>> }
>> ```
>>
>> Also, it's intellectually unsatisfying that I can't specify concurrency
>> for all the async calls in
>>
>> ```
>> await foo();
>> await bar();
>> for (const thing of things) await thing();
>> await baz();
>> ```
>>
>> Bob
>>
>>
>>
>> On Sat, Sep 7, 2019 at 8:17 AM Tom Boutell  wrote:
>>
>>> *REVISED PROPOSAL (thanks for the input so far!)*
>>>
>>> *Background*
>>>
>>> Developers learning async programming in the modern async/await era
>>> frequently discover this useful pattern:
>>>
>>> ```js
>>> for (item of items) {
>>>   await db.insert(item);
>>>   // additional awaited operations, etc.
>>> }
>>> ```
>>>
>>> This pattern extends the readability of "await" to cases where each item
>>> in an array, or each item in an iterable, requires some asynchronous
>>> processing. It also ensures that items are processed one at a time,
>>> avoiding unbounded concurrency that results in excessive stress on back
>>> ends, triggers API rate limiting, and otherwise results in unpredictable
>>> bugs.
>>>
>>> However, a common next step is to wish for a manageable level of
>>> concurrency. For instance, processing 500 asynchronous calls at once is
>>> unwise, especially in a web application that is already handling 100
>>> requests at once. But, processing 5 at once may be reasonable and improve
>>> the processing time per request.
>>>
>>> Unfortunately, at present, this requires shifting mental gears from
>>> async/await to promises. Here is an example based on Bluebird, there are of
>>> course other libraries for this:
>>>
>>> ```js
>>> const Promise = require('bluebird');
>>> await Promise.map(items, async function(item) {
>>>   await db.insert(item);
>>>   // additional awaited operations, etc.
>>> }, *{ concurrency: 5 }*);
>>> ```
>>>
>>> While effective, this is a lot of boilerplate and a shift of mental
>>> model. And in my experience as a mentor to many developers, this is *the
>>> only situation in which they frequently need to reach for a promise
>>> library. *A language feature to naturally integrate it with async/await
>>> would substantially expand the effectiveness of async/await as a tool for
>>> reducing the cognitive load of asynchronous programming.
>>>
>>> *Proposed Feature*
>>>
>>> I propose extending the existing async / await syntax to accommodate 
>>> *specifying
>>> the concurrency of a for...of loop:*
>>>
>>> ```js
>>> for (item of items *concurrency 5*) {
>>>   // db.insert is an async function
>>>   await db.insert(item);
>>> }
>>> console.log('Processing Complete');
>>> ```
>>>
>>> The major benefit here is that *the developer does not have to shift
>>> gears mentally from async/await to thinking about promises to deal with a
>>> common case in systems programming. *They are able to continue with the
>>> pattern they are already comfortable with.
>>>
>>> Up to 5 loop bodies commence concurrently with regard to "await"
>>> statements (see below).
>>>
>>> There is no guarantee that item 3 will finish before item 2, or that
>>> item 4 won't start (due to 3 being finished) before item 2 ends, etc.
>>>
>>> If an exception is not caught inside the loop body, the loop stops, that
>>> exception is thrown beyond the loop, and any further exceptions from that
>>> invocation of the loop due to concurrently executing loop bodies are
>>> discarded.
>>>
>>> Just as with an ordinary "for...of" loop containing an "await"
>>> statement, *it is guaranteed that, barring an exception, the loop body
>>> will execute completely for every item in "items" before the loop exits and
>>> the console.log statement executes.* The only difference is that *the
>>> specified amount of concurrency is permitted during the loop*.
>>>
>>> "5" may be any expression resulting in a number. It is cast to an
>>> integer. If  the result is not a natural number, an error is thrown (it
>>> must not be 0 or a negative number).
>>>
>>> *FAQs*
>>>
>>> *"What if I want unlimited 

Re: Stage 0 proposal: specifying concurrency for "for...of" loops potentially containing "await" statements

2019-09-07 Thread Tom Boutell
Up to five instances of the loop body would be in progress, assuming at
least one of them awaits at some point. any await inside the loop body
would be respected with regard to code that follows it in the loop body.
The only place concurrency comes into play is that more than one of these
loopbodies could be in progress for separate items, for instance they could
all be awaiting  a long database operation or API call. To avoid the
frequent problems that come up with unlimited concurrency when dealing with
apis and similar, you set the concurrency so that you don't exceed those
reasonable limits.

On Sat, Sep 7, 2019, 12:24 PM Bob Myers  wrote:

> I don't understand how this would work.
>
> ```
> for (const thing of things concurrency 5) {
>   const result = await thing();
>   console.log(result); // <== what is `result` here, if the call to
> thing() hasn't completed?
> }
> ```
>
> Also, it's intellectually unsatisfying that I can't specify concurrency
> for all the async calls in
>
> ```
> await foo();
> await bar();
> for (const thing of things) await thing();
> await baz();
> ```
>
> Bob
>
>
>
> On Sat, Sep 7, 2019 at 8:17 AM Tom Boutell  wrote:
>
>> *REVISED PROPOSAL (thanks for the input so far!)*
>>
>> *Background*
>>
>> Developers learning async programming in the modern async/await era
>> frequently discover this useful pattern:
>>
>> ```js
>> for (item of items) {
>>   await db.insert(item);
>>   // additional awaited operations, etc.
>> }
>> ```
>>
>> This pattern extends the readability of "await" to cases where each item
>> in an array, or each item in an iterable, requires some asynchronous
>> processing. It also ensures that items are processed one at a time,
>> avoiding unbounded concurrency that results in excessive stress on back
>> ends, triggers API rate limiting, and otherwise results in unpredictable
>> bugs.
>>
>> However, a common next step is to wish for a manageable level of
>> concurrency. For instance, processing 500 asynchronous calls at once is
>> unwise, especially in a web application that is already handling 100
>> requests at once. But, processing 5 at once may be reasonable and improve
>> the processing time per request.
>>
>> Unfortunately, at present, this requires shifting mental gears from
>> async/await to promises. Here is an example based on Bluebird, there are of
>> course other libraries for this:
>>
>> ```js
>> const Promise = require('bluebird');
>> await Promise.map(items, async function(item) {
>>   await db.insert(item);
>>   // additional awaited operations, etc.
>> }, *{ concurrency: 5 }*);
>> ```
>>
>> While effective, this is a lot of boilerplate and a shift of mental
>> model. And in my experience as a mentor to many developers, this is *the
>> only situation in which they frequently need to reach for a promise
>> library. *A language feature to naturally integrate it with async/await
>> would substantially expand the effectiveness of async/await as a tool for
>> reducing the cognitive load of asynchronous programming.
>>
>> *Proposed Feature*
>>
>> I propose extending the existing async / await syntax to accommodate 
>> *specifying
>> the concurrency of a for...of loop:*
>>
>> ```js
>> for (item of items *concurrency 5*) {
>>   // db.insert is an async function
>>   await db.insert(item);
>> }
>> console.log('Processing Complete');
>> ```
>>
>> The major benefit here is that *the developer does not have to shift
>> gears mentally from async/await to thinking about promises to deal with a
>> common case in systems programming. *They are able to continue with the
>> pattern they are already comfortable with.
>>
>> Up to 5 loop bodies commence concurrently with regard to "await"
>> statements (see below).
>>
>> There is no guarantee that item 3 will finish before item 2, or that item
>> 4 won't start (due to 3 being finished) before item 2 ends, etc.
>>
>> If an exception is not caught inside the loop body, the loop stops, that
>> exception is thrown beyond the loop, and any further exceptions from that
>> invocation of the loop due to concurrently executing loop bodies are
>> discarded.
>>
>> Just as with an ordinary "for...of" loop containing an "await" statement, *it
>> is guaranteed that, barring an exception, the loop body will execute
>> completely for every item in "items" before the loop exits and the
>> console.log statement executes.* The only difference is that *the
>> specified amount of concurrency is permitted during the loop*.
>>
>> "5" may be any expression resulting in a number. It is cast to an
>> integer. If  the result is not a natural number, an error is thrown (it
>> must not be 0 or a negative number).
>>
>> *FAQs*
>>
>> *"What if I want unlimited concurrency?"*
>>
>> It is rarely a good idea. It results in excessive stress on back ends,
>> unnecessary guards that force serialization in interface libraries just to
>> cope with (and effectively negate) it, and API rate limiting. This feature
>> teaches the best practice that the 

Re: Stage 0 proposal: specifying concurrency for "for...of" loops potentially containing "await" statements

2019-09-07 Thread Bob Myers
I don't understand how this would work.

```
for (const thing of things concurrency 5) {
  const result = await thing();
  console.log(result); // <== what is `result` here, if the call to thing()
hasn't completed?
}
```

Also, it's intellectually unsatisfying that I can't specify concurrency for
all the async calls in

```
await foo();
await bar();
for (const thing of things) await thing();
await baz();
```

Bob



On Sat, Sep 7, 2019 at 8:17 AM Tom Boutell  wrote:

> *REVISED PROPOSAL (thanks for the input so far!)*
>
> *Background*
>
> Developers learning async programming in the modern async/await era
> frequently discover this useful pattern:
>
> ```js
> for (item of items) {
>   await db.insert(item);
>   // additional awaited operations, etc.
> }
> ```
>
> This pattern extends the readability of "await" to cases where each item
> in an array, or each item in an iterable, requires some asynchronous
> processing. It also ensures that items are processed one at a time,
> avoiding unbounded concurrency that results in excessive stress on back
> ends, triggers API rate limiting, and otherwise results in unpredictable
> bugs.
>
> However, a common next step is to wish for a manageable level of
> concurrency. For instance, processing 500 asynchronous calls at once is
> unwise, especially in a web application that is already handling 100
> requests at once. But, processing 5 at once may be reasonable and improve
> the processing time per request.
>
> Unfortunately, at present, this requires shifting mental gears from
> async/await to promises. Here is an example based on Bluebird, there are of
> course other libraries for this:
>
> ```js
> const Promise = require('bluebird');
> await Promise.map(items, async function(item) {
>   await db.insert(item);
>   // additional awaited operations, etc.
> }, *{ concurrency: 5 }*);
> ```
>
> While effective, this is a lot of boilerplate and a shift of mental model.
> And in my experience as a mentor to many developers, this is *the only
> situation in which they frequently need to reach for a promise library. *A 
> language
> feature to naturally integrate it with async/await would substantially
> expand the effectiveness of async/await as a tool for reducing the
> cognitive load of asynchronous programming.
>
> *Proposed Feature*
>
> I propose extending the existing async / await syntax to accommodate 
> *specifying
> the concurrency of a for...of loop:*
>
> ```js
> for (item of items *concurrency 5*) {
>   // db.insert is an async function
>   await db.insert(item);
> }
> console.log('Processing Complete');
> ```
>
> The major benefit here is that *the developer does not have to shift
> gears mentally from async/await to thinking about promises to deal with a
> common case in systems programming. *They are able to continue with the
> pattern they are already comfortable with.
>
> Up to 5 loop bodies commence concurrently with regard to "await"
> statements (see below).
>
> There is no guarantee that item 3 will finish before item 2, or that item
> 4 won't start (due to 3 being finished) before item 2 ends, etc.
>
> If an exception is not caught inside the loop body, the loop stops, that
> exception is thrown beyond the loop, and any further exceptions from that
> invocation of the loop due to concurrently executing loop bodies are
> discarded.
>
> Just as with an ordinary "for...of" loop containing an "await" statement, *it
> is guaranteed that, barring an exception, the loop body will execute
> completely for every item in "items" before the loop exits and the
> console.log statement executes.* The only difference is that *the
> specified amount of concurrency is permitted during the loop*.
>
> "5" may be any expression resulting in a number. It is cast to an integer.
> If  the result is not a natural number, an error is thrown (it must not be
> 0 or a negative number).
>
> *FAQs*
>
> *"What if I want unlimited concurrency?"*
>
> It is rarely a good idea. It results in excessive stress on back ends,
> unnecessary guards that force serialization in interface libraries just to
> cope with (and effectively negate) it, and API rate limiting. This feature
> teaches the best practice that the level of concurrency should be mindfully
> chosen. However, those who really want it can specify "concurrency
> items.length" or similar.
>
> *"What about async iterators?"*
>
> The feature should also be supported here:
>
> ```js
> for *async* (item of items *concurrency 5*) {
>   // db.insert is an async function
>   await db.insert(item);
> }
> ```
>
> While the async iterator itself is still sequential rather than
> concurrent, frequently these can supply values considerably faster than
> they are processed by the loop body, and so there is still potential
> benefit in having several items "in the hopper" (up to the concurrency
> limit) at a time.
>
> --
> Chief Software Architect
> Apostrophe Technologies
> Pronouns: he / him / his
> 

Re: [Proposal] Refer to actual value : keyword "itself"

2019-09-07 Thread Sultan
Can you currently do this with the "super" keyword outside of classes?

On Fri, Sep 6, 2019 at 9:16 PM Jordan Harband  wrote:

> `var itself = 3;` means that your choice of keyword wouldn't be an option;
> you'd be limited to something that was currently a syntax error.
>
> On Fri, Sep 6, 2019 at 2:53 AM Cyril Auburtin 
> wrote:
>
>> also optional-chaining will help
>> ```js
>> return {
>> ...state,
>> child: {
>> ...state?.child,
>> subchild: {
>> ...state?.child?.subchild,
>> property: (state?.child?.subchild?.property ?? 0) + 1
>> }
>> }
>> }
>> ```
>>
>> @Herby yes that's interesting, works in any order actually `const {child,
>> child: {subchild}} = state;`
>>
>> On Fri, Sep 6, 2019 at 11:23 AM Herby Vojčík  wrote:
>>
>>> On 6. 9. 2019 10:34, Cyril Auburtin wrote:
>>> > You could currently do
>>> > ```js
>>> > object.child.property /= 5
>>> > ```
>>> >
>>> > with destructuring:
>>> > ```js
>>> > const {child: {subchild}, child} = state;
>>>
>>> Wow, I didn't know I can do that. Nice.
>>>
>> ___
>> es-discuss mailing list
>> es-discuss@mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
> ___
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Stage 0 proposal: specifying concurrency for "for...of" loops potentially containing "await" statements

2019-09-07 Thread Tom Boutell
*REVISED PROPOSAL (thanks for the input so far!)*

*Background*

Developers learning async programming in the modern async/await era
frequently discover this useful pattern:

```js
for (item of items) {
  await db.insert(item);
  // additional awaited operations, etc.
}
```

This pattern extends the readability of "await" to cases where each item in
an array, or each item in an iterable, requires some asynchronous
processing. It also ensures that items are processed one at a time,
avoiding unbounded concurrency that results in excessive stress on back
ends, triggers API rate limiting, and otherwise results in unpredictable
bugs.

However, a common next step is to wish for a manageable level of
concurrency. For instance, processing 500 asynchronous calls at once is
unwise, especially in a web application that is already handling 100
requests at once. But, processing 5 at once may be reasonable and improve
the processing time per request.

Unfortunately, at present, this requires shifting mental gears from
async/await to promises. Here is an example based on Bluebird, there are of
course other libraries for this:

```js
const Promise = require('bluebird');
await Promise.map(items, async function(item) {
  await db.insert(item);
  // additional awaited operations, etc.
}, *{ concurrency: 5 }*);
```

While effective, this is a lot of boilerplate and a shift of mental model.
And in my experience as a mentor to many developers, this is *the only
situation in which they frequently need to reach for a promise
library. *A language
feature to naturally integrate it with async/await would substantially
expand the effectiveness of async/await as a tool for reducing the
cognitive load of asynchronous programming.

*Proposed Feature*

I propose extending the existing async / await syntax to accommodate
*specifying
the concurrency of a for...of loop:*

```js
for (item of items *concurrency 5*) {
  // db.insert is an async function
  await db.insert(item);
}
console.log('Processing Complete');
```

The major benefit here is that *the developer does not have to shift gears
mentally from async/await to thinking about promises to deal with a common
case in systems programming. *They are able to continue with the pattern
they are already comfortable with.

Up to 5 loop bodies commence concurrently with regard to "await" statements
(see below).

There is no guarantee that item 3 will finish before item 2, or that item 4
won't start (due to 3 being finished) before item 2 ends, etc.

If an exception is not caught inside the loop body, the loop stops, that
exception is thrown beyond the loop, and any further exceptions from that
invocation of the loop due to concurrently executing loop bodies are
discarded.

Just as with an ordinary "for...of" loop containing an "await" statement, *it
is guaranteed that, barring an exception, the loop body will execute
completely for every item in "items" before the loop exits and the
console.log statement executes.* The only difference is that *the
specified amount of concurrency is permitted during the loop*.

"5" may be any expression resulting in a number. It is cast to an integer.
If  the result is not a natural number, an error is thrown (it must not be
0 or a negative number).

*FAQs*

*"What if I want unlimited concurrency?"*

It is rarely a good idea. It results in excessive stress on back ends,
unnecessary guards that force serialization in interface libraries just to
cope with (and effectively negate) it, and API rate limiting. This feature
teaches the best practice that the level of concurrency should be mindfully
chosen. However, those who really want it can specify "concurrency
items.length" or similar.

*"What about async iterators?"*

The feature should also be supported here:

```js
for *async* (item of items *concurrency 5*) {
  // db.insert is an async function
  await db.insert(item);
}
```

While the async iterator itself is still sequential rather than concurrent,
frequently these can supply values considerably faster than they are
processed by the loop body, and so there is still potential benefit in
having several items "in the hopper" (up to the concurrency limit) at a
time.

-- 
Chief Software Architect
Apostrophe Technologies
Pronouns: he / him / his
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Re: Stage 0 proposal: specifying concurrency for "for...of" loops potentially containing "await" statements

2019-09-07 Thread Tom Boutell
Omitting the "await" would not suffice for the original use case of
"await": you need to know it actually completed before you continue to the
code *after* the "for" loop. It would also unleash unbounded concurrency
which usually doesn't end well.

It takes us back to:

"Sometimes my code works, sometimes it doesn't, I'm not sure why. Some kind
of timing thing?"

In my experience, the developers who try that approach have a terrible time
debugging their code later. This is why the ability to write "for...of"
loops with "await" has been such a big win for junior JavaScript developers.

As for variables outside the loop, they actually would behave reasonably.
For instance, this code would yield sensible results:

```js
const interval = setInterval(progressDisplay, 250);
let progress = 0;
for (const piece of pieces concurrency 5) {
  await db.insert(piece);
  progress++;
}
clearInterval(interval);

function progressDisplay() {
  console.log(progress + ' of ' + pieces.length + ' completed');
}
```

Even in more complex cases, keep in mind that this is just suspension via
"await", not preemptive multitasking, so the side effects are not that
strange.

Can you give an example of a situation where this would not behave
reasonably?

I can see that my proposal would be stronger if I removed "concurrently"
and kept only "concurrency N". That is the feature I really wanted, and
including "concurrently" was just a gesture to completeness but as others
have pointed out, it's not a completeness we want.

The only place unbounded concurrency really tends to make sense is when you
don't have a giant array of things to process - you have a handful of
predetermined tasks that you know can run concurrently. I can picture a
language feature for that, but it wouldn't involve "for...of" loops (:



On Sat, Sep 7, 2019 at 7:51 AM Naveen Chawla  wrote:

> In my mind there is a cognitive load cost in adding language constructs
> (unless they significantly otherwise reduce cognitive load). In this case,
> I find omitting the "await" would suffice for a lot of people, and for
> those who want the loop to conceptually "hang" until all are completed
> (which I find strange in of itself), I think synchronously collecting the
> operations then doing a Promise.all is more understandable to a reader. Can
> you imagine explaining a for loop that doesn't behave linearly, e.g.
> imagine you have a variable outside the loop that is being modified on each
> iteration - the whole thing would go haywire. Especially compared to
> building an array followed by a Promise.all.
>
> In my mind, the whole point of "await async" is to linearize asynchronous
> programming, so that logical flow that happens to be asynchronous is
> trivial to reason about, and read. In my mind the "concurrent" proposal
> jeopardises that.
>
> On Fri, 6 Sep 2019 at 22:05, Tom Boutell  wrote:
>
>> > Can someone tell me exactly how just omitting "await" doesn't broadly
>> achieve the "concurrency" objective?
>>
>> Omitting "await" gives us no assurance that all of the iterations
>> completed prior to exit from the "for...of" loop.
>>
>> My proposal should have specified that regardless of whether "concurrency
>> N" or "concurrent" is used, the loop will not exit until all of the items
>> have successfully executed the loop body.
>>
>> > It could be probably added as a Promise.all(iterable, concurrency?)
>>
>> While this would be a useful extension to Promise.all and might be part
>> of the underlying implementation of the language feature, this does not
>> meet the goal of avoiding the cognitive load of shifting gears from the
>> "async/await" pattern to thinking overtly about promises. There are similar
>> implementations, such as the one in Bluebird, but the goal of the language
>> feature is to expand the set of problems that can be solved without the
>> cognitive load of collecting async function return values and then awaiting
>> a library function that operates on them.
>>
>> My own belief is that the percentage of "await-friendly" use cases for
>> asynchronous programming that come up for most developers is pretty close
>> to 90%, and that a syntax for specifying concurrency would take it the rest
>> of the way there, and be much appreciated by the developer who has written
>> the "for...of { await ... }" loop and now wants to improve the performance
>> in a simple way that is also likely to be safe (bounded concurrency).
>>
>> --
>> Chief Software Architect
>> Apostrophe Technologies
>> Pronouns: he / him / his
>> ___
>> es-discuss mailing list
>> es-discuss@mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>

-- 
Chief Software Architect
Apostrophe Technologies
Pronouns: he / him / his
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Re: Stage 0 proposal: specifying concurrency for "for...of" loops potentially containing "await" statements

2019-09-07 Thread Naveen Chawla
In my mind there is a cognitive load cost in adding language constructs
(unless they significantly otherwise reduce cognitive load). In this case,
I find omitting the "await" would suffice for a lot of people, and for
those who want the loop to conceptually "hang" until all are completed
(which I find strange in of itself), I think synchronously collecting the
operations then doing a Promise.all is more understandable to a reader. Can
you imagine explaining a for loop that doesn't behave linearly, e.g.
imagine you have a variable outside the loop that is being modified on each
iteration - the whole thing would go haywire. Especially compared to
building an array followed by a Promise.all.

In my mind, the whole point of "await async" is to linearize asynchronous
programming, so that logical flow that happens to be asynchronous is
trivial to reason about, and read. In my mind the "concurrent" proposal
jeopardises that.

On Fri, 6 Sep 2019 at 22:05, Tom Boutell  wrote:

> > Can someone tell me exactly how just omitting "await" doesn't broadly
> achieve the "concurrency" objective?
>
> Omitting "await" gives us no assurance that all of the iterations
> completed prior to exit from the "for...of" loop.
>
> My proposal should have specified that regardless of whether "concurrency
> N" or "concurrent" is used, the loop will not exit until all of the items
> have successfully executed the loop body.
>
> > It could be probably added as a Promise.all(iterable, concurrency?)
>
> While this would be a useful extension to Promise.all and might be part of
> the underlying implementation of the language feature, this does not meet
> the goal of avoiding the cognitive load of shifting gears from the
> "async/await" pattern to thinking overtly about promises. There are similar
> implementations, such as the one in Bluebird, but the goal of the language
> feature is to expand the set of problems that can be solved without the
> cognitive load of collecting async function return values and then awaiting
> a library function that operates on them.
>
> My own belief is that the percentage of "await-friendly" use cases for
> asynchronous programming that come up for most developers is pretty close
> to 90%, and that a syntax for specifying concurrency would take it the rest
> of the way there, and be much appreciated by the developer who has written
> the "for...of { await ... }" loop and now wants to improve the performance
> in a simple way that is also likely to be safe (bounded concurrency).
>
> --
> Chief Software Architect
> Apostrophe Technologies
> Pronouns: he / him / his
> ___
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Optional chaining syntax but with the "mice" operator ?

2019-09-07 Thread Naveen Chawla
There has to be a better pattern than returning the "foo()" if the baz
property doesn't exist.

I'm curious what you would want to do with the resulting "foo()" anyway. I
can imagine a flow where I want "bar", and it doesn't exist it doesn't. I
cannot imagine wanting the "foo()" in place of it. There is type
unpredictability in the result, so subsequent operations would normally
expected to be impossible without type-branching. Hence my question to you
about what you would typically want to do with the "foo()" if that was the
returned result.

On Sat, 7 Sep 2019 at 12:08, Andrea Giammarchi 
wrote:

> Interesting I forgot about that, but it wouldn't cover the "trap here" use
> case.
>
> foo().bar ?! what => what : what;
>
> I'd like to forward foo() here
>
> On Sat, Sep 7, 2019, 11:45 Michael Luder-Rosefield 
> wrote:
>
>> This is getting very reminiscent of my 'forwarding ternary' operator (or
>> whatever I called it) I suggested a couple of years ago. I believe you were
>> involved in the discussion, Andrea...!
>>
>> ```
>> const val = foo() ?!
>>   (x) => x.bar.baz :
>>   someFallbackValue;
>> ```
>>
>> On Sat, 7 Sep 2019, 10:17 Andrea Giammarchi, 
>> wrote:
>>
>>> To better answer, let's start dropping any direct access and put a
>>> payload in the mix.
>>>
>>> As example, in the `foo()?.bar.baz` case, you might end up having `null`
>>> or `undefined`, as result, because `foo().bar` existed, but `bar.baz`
>>> didn't.
>>>
>>> In the `foo()?.bar?.baz` case, you might end up having `foo().bar`,
>>> because `bar.baz` didn't exist.
>>>
>>> But what if you are not interested in the whole chain, but only in a
>>> main specific point in such chain? In that case you would have
>>> `foo()?.bar.baz ?? foo()`, but you wouldn't know how to obtain that via
>>> `foo()?.bar?.baz ?? foo()`, because the latest one might result into
>>> `foo().bar`.
>>>
>>> Moreover, in both cases you'll end up multiplying the payload at least *
>>> 2, while the mouse trap will work like this:
>>>
>>> ```js
>>> foo()>> ```
>>>
>>> if either `foo().bar` or `bar.baz` don't exist, the returned result is
>>> `foo()`, and it's computed once. You don't care about `foo().bar` if
>>> `bar.baz` is not there, 'cause you want to retrieve `foo()` whenever you
>>> have a failure down the chain.
>>>
>>> Specially with DB operations, this is a very common case (abstraction
>>> layers all have somehow different nested objects with various info) and the
>>> specific info you want to know is usually attached at the top level bject,
>>> while crawling its sub properties either leads to the expected result or
>>> you're left clueless about the result, 'cause all info got lost in the
>>> chain.
>>>
>>> The `foo()>> `foo().bar` existed, there's no way to expect `foo()` as result, and if
>>> it's `bar` that you're after you can write instead `foo()?.bar>> that if `baz` is not there, `bar` it is.
>>>
>>> This short-circuit the need for `??` in most cases, 'cause you already
>>> point at the desired result in the chain in case the result would be `null`
>>> or `undefined`.
>>>
>>> However, `??` itself doesn't provide any ability to reach any point in
>>> the previous chain that failed, so that once again, you find yourself
>>> crawling such chain as fallback, resulting potentially in multiple chains
>>> and repeated payloads.
>>>
>>> ```js
>>> // nested chains
>>> foo()?.bar.baz?.biz ?? foo()?.bar.baz ?? foo()?.bar;
>>>
>>> // mouse trap
>>> foo()?.bar>> ```
>>>
>>> Above example would prefer `foo().bar` if it exists, and if either
>>> `bar.baz` or `bar.baz.biz` returned `null` or `undefined`.
>>>
>>> I hope this clarifies further the intent, or the simplification, that
>>> such operator offers: it's a complementary hint for any optional chain, it
>>> doesn't have to be used, but when it does, it's visually semantic in its
>>> intent (at least to my eyes).
>>>
>>> Regards
>>>
>>>
>>>
>>>
>>> On Fri, Sep 6, 2019 at 11:20 PM Tab Atkins Jr. 
>>> wrote:
>>>
 On Fri, Sep 6, 2019 at 8:04 AM Andrea Giammarchi
  wrote:
 > Indeed I'm not super convinced myself about the "branching issue"
 'cause `const result = this?.is?.branching?.already` and all I am proposing
 is to hint the syntax where to stop in case something else fails down the
 line, as in `const result = this.?.is>>> other part is not reached, there is a certain point to keep going (which
 is, example, checking that `result !== this`)

 Important distinction there is that ?. only "branches" between the
 intended type and undefined, not between two arbitrary types. The
 cognitive load between those two is significantly different.

 In particular, you can't *do* anything with undefined, so
 `foo?.bar.baz` has pretty unambiguous semantics - you don't think you
 might be accessing the .baz property of undefined, because that
 clearly doesn't exist.

 That's not the case with mouse, where it's not clear, at least to me,
 whether `foo>>> 

Re: Optional chaining syntax but with the "mice" operator ?

2019-09-07 Thread Andrea Giammarchi
Interesting I forgot about that, but it wouldn't cover the "trap here" use
case.

foo().bar ?! what => what : what;

I'd like to forward foo() here

On Sat, Sep 7, 2019, 11:45 Michael Luder-Rosefield 
wrote:

> This is getting very reminiscent of my 'forwarding ternary' operator (or
> whatever I called it) I suggested a couple of years ago. I believe you were
> involved in the discussion, Andrea...!
>
> ```
> const val = foo() ?!
>   (x) => x.bar.baz :
>   someFallbackValue;
> ```
>
> On Sat, 7 Sep 2019, 10:17 Andrea Giammarchi, 
> wrote:
>
>> To better answer, let's start dropping any direct access and put a
>> payload in the mix.
>>
>> As example, in the `foo()?.bar.baz` case, you might end up having `null`
>> or `undefined`, as result, because `foo().bar` existed, but `bar.baz`
>> didn't.
>>
>> In the `foo()?.bar?.baz` case, you might end up having `foo().bar`,
>> because `bar.baz` didn't exist.
>>
>> But what if you are not interested in the whole chain, but only in a main
>> specific point in such chain? In that case you would have `foo()?.bar.baz
>> ?? foo()`, but you wouldn't know how to obtain that via `foo()?.bar?.baz ??
>> foo()`, because the latest one might result into `foo().bar`.
>>
>> Moreover, in both cases you'll end up multiplying the payload at least *
>> 2, while the mouse trap will work like this:
>>
>> ```js
>> foo()> ```
>>
>> if either `foo().bar` or `bar.baz` don't exist, the returned result is
>> `foo()`, and it's computed once. You don't care about `foo().bar` if
>> `bar.baz` is not there, 'cause you want to retrieve `foo()` whenever you
>> have a failure down the chain.
>>
>> Specially with DB operations, this is a very common case (abstraction
>> layers all have somehow different nested objects with various info) and the
>> specific info you want to know is usually attached at the top level bject,
>> while crawling its sub properties either leads to the expected result or
>> you're left clueless about the result, 'cause all info got lost in the
>> chain.
>>
>> The `foo()> `foo().bar` existed, there's no way to expect `foo()` as result, and if
>> it's `bar` that you're after you can write instead `foo()?.bar> that if `baz` is not there, `bar` it is.
>>
>> This short-circuit the need for `??` in most cases, 'cause you already
>> point at the desired result in the chain in case the result would be `null`
>> or `undefined`.
>>
>> However, `??` itself doesn't provide any ability to reach any point in
>> the previous chain that failed, so that once again, you find yourself
>> crawling such chain as fallback, resulting potentially in multiple chains
>> and repeated payloads.
>>
>> ```js
>> // nested chains
>> foo()?.bar.baz?.biz ?? foo()?.bar.baz ?? foo()?.bar;
>>
>> // mouse trap
>> foo()?.bar> ```
>>
>> Above example would prefer `foo().bar` if it exists, and if either
>> `bar.baz` or `bar.baz.biz` returned `null` or `undefined`.
>>
>> I hope this clarifies further the intent, or the simplification, that
>> such operator offers: it's a complementary hint for any optional chain, it
>> doesn't have to be used, but when it does, it's visually semantic in its
>> intent (at least to my eyes).
>>
>> Regards
>>
>>
>>
>>
>> On Fri, Sep 6, 2019 at 11:20 PM Tab Atkins Jr. 
>> wrote:
>>
>>> On Fri, Sep 6, 2019 at 8:04 AM Andrea Giammarchi
>>>  wrote:
>>> > Indeed I'm not super convinced myself about the "branching issue"
>>> 'cause `const result = this?.is?.branching?.already` and all I am proposing
>>> is to hint the syntax where to stop in case something else fails down the
>>> line, as in `const result = this.?.is>> other part is not reached, there is a certain point to keep going (which
>>> is, example, checking that `result !== this`)
>>>
>>> Important distinction there is that ?. only "branches" between the
>>> intended type and undefined, not between two arbitrary types. The
>>> cognitive load between those two is significantly different.
>>>
>>> In particular, you can't *do* anything with undefined, so
>>> `foo?.bar.baz` has pretty unambiguous semantics - you don't think you
>>> might be accessing the .baz property of undefined, because that
>>> clearly doesn't exist.
>>>
>>> That's not the case with mouse, where it's not clear, at least to me,
>>> whether `foo>> `foo.bar.baz ? foo.bar.baz : foo` or even `foo.bar ? foo.bar.baz :
>>> foo`. All three seem at least somewhat reasonable, and definitely
>>> *believable* as an interpretation!
>>>
>>> ~TJ
>>>
>> ___
>> es-discuss mailing list
>> es-discuss@mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Optional chaining syntax but with the "mice" operator ?

2019-09-07 Thread Michael Luder-Rosefield
This is getting very reminiscent of my 'forwarding ternary' operator (or
whatever I called it) I suggested a couple of years ago. I believe you were
involved in the discussion, Andrea...!

```
const val = foo() ?!
  (x) => x.bar.baz :
  someFallbackValue;
```

On Sat, 7 Sep 2019, 10:17 Andrea Giammarchi, 
wrote:

> To better answer, let's start dropping any direct access and put a payload
> in the mix.
>
> As example, in the `foo()?.bar.baz` case, you might end up having `null`
> or `undefined`, as result, because `foo().bar` existed, but `bar.baz`
> didn't.
>
> In the `foo()?.bar?.baz` case, you might end up having `foo().bar`,
> because `bar.baz` didn't exist.
>
> But what if you are not interested in the whole chain, but only in a main
> specific point in such chain? In that case you would have `foo()?.bar.baz
> ?? foo()`, but you wouldn't know how to obtain that via `foo()?.bar?.baz ??
> foo()`, because the latest one might result into `foo().bar`.
>
> Moreover, in both cases you'll end up multiplying the payload at least *
> 2, while the mouse trap will work like this:
>
> ```js
> foo() ```
>
> if either `foo().bar` or `bar.baz` don't exist, the returned result is
> `foo()`, and it's computed once. You don't care about `foo().bar` if
> `bar.baz` is not there, 'cause you want to retrieve `foo()` whenever you
> have a failure down the chain.
>
> Specially with DB operations, this is a very common case (abstraction
> layers all have somehow different nested objects with various info) and the
> specific info you want to know is usually attached at the top level bject,
> while crawling its sub properties either leads to the expected result or
> you're left clueless about the result, 'cause all info got lost in the
> chain.
>
> The `foo() `foo().bar` existed, there's no way to expect `foo()` as result, and if
> it's `bar` that you're after you can write instead `foo()?.bar that if `baz` is not there, `bar` it is.
>
> This short-circuit the need for `??` in most cases, 'cause you already
> point at the desired result in the chain in case the result would be `null`
> or `undefined`.
>
> However, `??` itself doesn't provide any ability to reach any point in the
> previous chain that failed, so that once again, you find yourself crawling
> such chain as fallback, resulting potentially in multiple chains and
> repeated payloads.
>
> ```js
> // nested chains
> foo()?.bar.baz?.biz ?? foo()?.bar.baz ?? foo()?.bar;
>
> // mouse trap
> foo()?.bar ```
>
> Above example would prefer `foo().bar` if it exists, and if either
> `bar.baz` or `bar.baz.biz` returned `null` or `undefined`.
>
> I hope this clarifies further the intent, or the simplification, that such
> operator offers: it's a complementary hint for any optional chain, it
> doesn't have to be used, but when it does, it's visually semantic in its
> intent (at least to my eyes).
>
> Regards
>
>
>
>
> On Fri, Sep 6, 2019 at 11:20 PM Tab Atkins Jr. 
> wrote:
>
>> On Fri, Sep 6, 2019 at 8:04 AM Andrea Giammarchi
>>  wrote:
>> > Indeed I'm not super convinced myself about the "branching issue"
>> 'cause `const result = this?.is?.branching?.already` and all I am proposing
>> is to hint the syntax where to stop in case something else fails down the
>> line, as in `const result = this.?.is> other part is not reached, there is a certain point to keep going (which
>> is, example, checking that `result !== this`)
>>
>> Important distinction there is that ?. only "branches" between the
>> intended type and undefined, not between two arbitrary types. The
>> cognitive load between those two is significantly different.
>>
>> In particular, you can't *do* anything with undefined, so
>> `foo?.bar.baz` has pretty unambiguous semantics - you don't think you
>> might be accessing the .baz property of undefined, because that
>> clearly doesn't exist.
>>
>> That's not the case with mouse, where it's not clear, at least to me,
>> whether `foo> `foo.bar.baz ? foo.bar.baz : foo` or even `foo.bar ? foo.bar.baz :
>> foo`. All three seem at least somewhat reasonable, and definitely
>> *believable* as an interpretation!
>>
>> ~TJ
>>
> ___
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Optional chaining syntax but with the "mice" operator ?

2019-09-07 Thread Andrea Giammarchi
To better answer, let's start dropping any direct access and put a payload
in the mix.

As example, in the `foo()?.bar.baz` case, you might end up having `null` or
`undefined`, as result, because `foo().bar` existed, but `bar.baz` didn't.

In the `foo()?.bar?.baz` case, you might end up having `foo().bar`, because
`bar.baz` didn't exist.

But what if you are not interested in the whole chain, but only in a main
specific point in such chain? In that case you would have `foo()?.bar.baz
?? foo()`, but you wouldn't know how to obtain that via `foo()?.bar?.baz ??
foo()`, because the latest one might result into `foo().bar`.

Moreover, in both cases you'll end up multiplying the payload at least * 2,
while the mouse trap will work like this:

```js
foo() wrote:

> On Fri, Sep 6, 2019 at 8:04 AM Andrea Giammarchi
>  wrote:
> > Indeed I'm not super convinced myself about the "branching issue" 'cause
> `const result = this?.is?.branching?.already` and all I am proposing is to
> hint the syntax where to stop in case something else fails down the line,
> as in `const result = this.?.is part is not reached, there is a certain point to keep going (which is,
> example, checking that `result !== this`)
>
> Important distinction there is that ?. only "branches" between the
> intended type and undefined, not between two arbitrary types. The
> cognitive load between those two is significantly different.
>
> In particular, you can't *do* anything with undefined, so
> `foo?.bar.baz` has pretty unambiguous semantics - you don't think you
> might be accessing the .baz property of undefined, because that
> clearly doesn't exist.
>
> That's not the case with mouse, where it's not clear, at least to me,
> whether `foo `foo.bar.baz ? foo.bar.baz : foo` or even `foo.bar ? foo.bar.baz :
> foo`. All three seem at least somewhat reasonable, and definitely
> *believable* as an interpretation!
>
> ~TJ
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Stage 0 proposal: specifying concurrency for "for...of" loops potentially containing "await" statements

2019-09-07 Thread Cyril Auburtin
> With the promise.all, would each item in the iterable be an async
function (or function returning a promise)?  I mean, I'm presuming the
point is to not have every item execute at the same time.

Ah, correct, like in my [example](
https://github.com/caub/misc/blob/master/utils/promise-concurrent.js) it
should be an array of thunks (function with no arguments returning the
promise)

So it should also have a different name than `Promise.all`,
`Promise.allThunks` maybe?

On Fri, Sep 6, 2019 at 10:08 PM Michael J. Ryan  wrote:

> With the promise.all, would each item in the iterable be an async function
> (or function returning a promise)?  I mean, I'm presuming the point is to
> not have every item execute at the same time.
>
> --
>
> Michael J. Ryan
> Website: https://www.tracker1.info/
> Email: track...@gmail.com
> Mobile: 480-270-4509
>
>
> On Fri, Sep 6, 2019 at 12:04 PM Cyril Auburtin 
> wrote:
>
>> It could be probably added as a `Promise.all(iterable, concurrency?)`
>>
>> Some existing implementations:
>> - http://bluebirdjs.com/docs/api/promise.map.html
>> - https://caolan.github.io/async/v3/docs.html#mapLimit
>> - I tried to write one:
>> https://github.com/caub/misc/blob/master/utils/promise-concurrent.js
>>
>> On Fri, Sep 6, 2019 at 8:33 PM Tom Boutell  wrote:
>>
>>> I am more interested in syntax two than syntax one, which I felt should
>>> probably be included for completeness. But hey, as you say, maybe not since
>>> unguarded concurrency is indeed usually a mistake.
>>>
>>> Taken on its own, do you have an objection to `for (item of items
>>> concurrency 5) { ... }`?
>>>
>>>
>>> On Fri, Sep 6, 2019 at 1:46 PM C. Scott Ananian 
>>> wrote:
>>>
 The current way to write what you want is:

 await Promise.all(itemsCursor.map(item => db.insert(item));

 or

 await Promise.all(itemsCursor.map(Promise.guard(5, item =>
 db.insert(item;

 if you are using a library like `prfun` (
 https://github.com/cscott/prfun#promiseguardfunctionnumber-condition-function-fn--function
 ).

 I'm not sure adding a new parallel loop construct is an obvious
 improvement on this, especially since unguarded concurrent execution is
 usually a mistake (can cause memory requirements to blow up), as you point
 out yourself.

 I'd be more in favor of new syntax if it was integrated with a
 work-stealing mechanism, since (a) that can't as easily be done in a
 library function (you need access to the entire set of runnable tasks, not
 just the ones created in this loop), and (b) is more likely to be
 correct/fast by default and not lead to subtle resource-exhaustion 
 problems.
   --scott

 On Fri, Sep 6, 2019 at 12:40 PM Tom Boutell 
 wrote:

> *Specifying concurrency for "for...of" loops potentially containing
> "await" statements in the loop body*
>
> In the async/await era, I see most developers using the async and
> await keywords in 90% of situations, shifting to "Promise.all" or the
> bluebird library only to cope with concurrency issues.
>
> The most common case in my experience is the need to admit a
> manageable level of parallelism when iterating a large array (or iterator,
> see the final section) and performing asynchronous work on each item.
> Unlimited concurrency (Promise.all) tends to overwhelm backends involved 
> in
> a way that confuses developers as to what is happening. Bluebird's
> "Promise.map" permits concurrency to be specified, which is great, but
> requires pulling in a library and switching of mental gears ("OK right,
> these async functions return promises," etc).
>
> To build on the friendliness of async/await, I propose these two
> syntaxes be accepted:
>
> SYNTAX ONE
>
> ```js
> for (item of items concurrent) {
>   // db.insert is an async function
>   await db.insert(item);
> }
> ```
>
> In Syntax One, all loop bodies commence concurrently (see below for
> the definition of "concurrently" with regard to async). If an exception is
> not caught inside the loop, it is thrown beyond the loop, and all
> exceptions subsequently thrown by concurrently executing loop bodies are
> discarded (like Promise.all).
>
> *While I feel that unlimited concurrency is usually a mistake in a
> situation where you have an array of items of unpredictable number, it
> seems odd not to have a syntax for this case, and "concurrency 0" seems
> clunky.*
>
> SYNTAX TWO
>
> ```js
> for (item of items concurrency 5) {
>   // db.insert is an async function
>   await db.insert(item);
> }
> ```
>
> in Syntax Two, up to 5 loop bodies commence concurrently (see below).
> There is no guarantee that item 3 will finish before item 2, or that item 
> 4
> won't start (due to 3 being finished) before item 2