dart-lang / dart-lang/language
Generator expressions / Iterable literals and Stream literals
Nobody has claimed this yet.
- Dominant language
- TeX
- Stars
- 2.9k
- Forks
- 239
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 14
Description
In dart we have literal expressions for lists, sets, and maps. I propose that we also allow for expressions that generate iterables and streams.
Take for example this code:
```dart
List> pythagorean = [
for (int a = 0; a < 100; a++)
for (int b = a; b < 100; b++)
for (int c = b; c < 100; c++)
if (a * a + b * b == c * c) [a, b, c],
];
```
If we wanted to instead generate an `Iterable>` we could do that with a [generator function](https://dart.dev/guides/language/language-tour#generators) using the `sync*` keyword. We can even use `sync*` on lambda expressions which looks like the following:
```dart
Iterable> pythagoreanSynchronous = (() sync* {
for (int a = 0; a < 100; a++)
for (int b = a; b < 100; b++)
for (int c = b; c < 100; c++)
if (a * a + b * b == c * c) yield [a, b, c];
})();
```
I propose that we could generate an `Iterable` by placing the `sync*` keyword before a list literal, which would be syntactic sugar for the above:
```dart
Iterable> pythagoreanSynchronous = sync* [
for (int a = 0; a < 100; a++)
for (int b = a; b < 100; b++)
for (int c = b; c < 100; c++)
if (a * a + b * b == c * c) [a, b, c],
];
```
Similarly using the `async*` keyword would instead generate a stream:
```dart
Stream> pythagoreanAsynchronous = async* [
for (int a = 0; a < 100; a++)
for (int b = a; b < 100; b++)
for (int c = b; c < 100; c++)
if (a * a + b * b == c * c) [a, b, c],
];
```
Of course when generating streams, you would likely want to use await within the context of the expression, so you should be able to do the following as well:
```dart
Future> combineNumbers(int a, int b, int c) async => [a,b,c];
Stream> pythagoreanAsynchronous = async* [
for (int a = 0; a < 100; a++)
for (int b = a; b < 100; b++)
for (int c = b; c < 100; c++)
if (a * a + b * b == c * c) await combineNumbers(a, b, c),
];
```
Which would be syntactic sugar for:
```dart
Stream> pythagoreanAsynchronous = (() async* {
for (int a = 0; a < 100; a++)
for (int b = a; b < 100; b++)
for (int c = b; c < 100; c++)
if (a * a + b * b == c * c)
yield await combineNumbers(a, b, c);
})();
```
Should support spreads as well:
```dart
Iterable pythagoreanSynchronousFlattened = sync* [
for (int a = 0; a < 100; a++)
for (int b = a; b < 100; b++)
for (int c = b; c < 100; c++)
if (a * a + b * b == c * c) ...[a, b, c],
];
```
Which is equivalent to:
```dart
Iterable pythagoreanSynchronousFlattened = (() sync* {
for (int a = 0; a < 100; a++)
for (int b = a; b < 100; b++)
for (int c = b; c < 100; c++)
if (a * a + b * b == c * c)
for (var item in [a, b, c]) yield item;
})();
```
Raw values like:
```dart
sync* [1, 2, 3];
```
Are equivalent to:
```dart
(() sync* { yield 1; yield 2; yield 3; })();
```
Generator expressions already exist in the python programming language (https://www.python.org/dev/peps/pep-0289/).
I feel this would make working with lazy collections in dart even easier.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The issue names no repository files or tests. Start by reviewing the proposed list, spread, sync*, and async* examples and the linked Dart generator documentation. This is design work: done would require a decided syntax and semantics for iterable and stream literals, including spreads and await handling.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 20/100