Proposal - generator literals

Add a new literal type that:

  • Has an iterable value;
  • Has syntax similar to the existing array literal, including spread notation;
  • Evaluates its element sub-expressions lazily, as its value is iterated over.

The full text and a reference implementation (a Babel fork) are available here: babel-tc39-generator-literals/packages/babel-plugin-proposal-generator-literals at generator-literals · MaxMotovilov/babel-tc39-generator-literals · GitHub

The proposal has stemmed from a recent discussion on this forum and I would like to credit bergus with the original idea that evolved into this proposal.

2 Likes
  1. I love the proposal, and it'd complement the iterator helpers proposal greatly.
  2. I'd recommend enabling issues in proposal repos before posting them here - it'd be very helpful.
  3. Your syntax potentially conflicts with multiplication. (Consider: a <newline> * [ 1 ]) This could be worked around via precedence hacking, but is worth taking into consideration.
  4. Have you considered async iterables, too? Support for async iterables would trivialize things like stream concatenation and header/footer appending for one.

Done!

Your example is well formed syntactically, but not semantically, right? From a practical standpoint, the implementation should not be confused as *[ is recognized by the tokenizer (similar to e.g. a- -(b) vs a-- (b) as the latter is also syntactically but not semantically well formed). However if this is, indeed, considered a problem, an alternative syntax could be [* ... ].

Not seriously yet, as I'd rather be taking baby steps; besides I'd need quite a bit more time to implement this than I really could afford just now -- and here's a plug for my current employer, System 1, for accepting this implementation as a project for the internal hackathon :stuck_out_tongue: thus giving me a sorely needed timeslice.

With + and - it's obvious due to lhs ++ rhs invalid while (lhs + +rhs, lhs+ + rhs) valid. But with * it's little bit different story due to both lhs ** rhs and lhs * rhs is valid.

So probably same tokenization approach could by apply to differentiate a ** [...] from a * *[...]

I take it you're referring to ** exponentiation? Same argument applies to it as to multiplication. BTW a-- (b) appears to be syntactically valid -- applying postfix function call to the result of postfix decrement -- although of course senseless semantically, same as multiplying by (or exponentiating to) an array.

It's technically possible to have breaking syntactic changes (see: let destructuring), and it's worth exploring. But even if it's decided that a breaking syntax change is okay, it's still worth bringing up.

That's fair, and I wasn't saying you had to implement it now. It just plays into my previous point because async isn't a reserved keyword (though if we can break code with iterables, we can also almost certainly break code with async * [ <expr> ] as well).

There seems to be no immediate need to address with async generator literals; if the enumerated values are effectively async expressions yielding promises, those may be awaited by the caller (the original Promise.all() scenario falls loosely into this category). I can see two scenarios in which the generator has to be async:

  1. A generated values creates, by side effect, a promise that has to be awaited to produce a subsequent generated value.
  2. A spread operator applied to an async iterable.

Both cases do exhibit a need for syntactically distinct async variety of the generator literal (as you say, async *[ or possibly async [*). I can't however claim enough insight at this point to propose a complete facility.

1 Like