dart-lang / dart-lang/language

Generator expressions / Iterable literals and Stream literals

Open
#1,633 16 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.