dart-lang / language

Design of the Dart language
Other
2.65k stars 201 forks source link

await for ... on ... catch syntax #1441

Open lukepighetti opened 3 years ago

lukepighetti commented 3 years ago

There is currently no way that I am aware of to handle stream errors in await for loops without breaking the loop.

/// This works, but any error will break the loop and close the subscription
try {
  await for (var e in service.probeEvents()) {
    status = status.copyWith(probes: e);
    yield status;
  }
} on StreamException {
  ///
} catch (e) {
  ///
}

I am proposing that we add syntax on await for as an added feature.

/// Proposing this syntax, where errors will not break the loop
await for (var e in service.probeEvents()) {
  status = status.copyWith(probes: e);
  yield status;
} on StreamException {
  ///
} catch (e) {
  ///
} finally {
  /// onDone
}
lrhn commented 3 years ago

(Edit: Focusing on the issue at hand, instead of getting sidetracked into ideas for other features).

Catching the situation where a stream emits an error in an await for:

await for (var e in stream) {
  body
} on SomeError catch (e) {
  catchBody
}

makes a kind of sense. It corresponds to the onError handler of Stream.listen.

It feels right-ish to me that it comes after the body, but attached to the same loop.

Most streams do not have multiple errors, or errors that are not fatal, but there are some. (Maybe that was a bad idea, but for broadcast streams it felt right). This is not something which is important often, but it is relevant in some cases, and not supported.

Should we also allow finally (for the onDone)? Probably not, it seems like a job for else from #171 instead.

(It's very hard to create errors inside streams using async* syntax because the only way to emit an error is yield*'ing a stream containing an error, like yield* Stream.error(theError);. Maybe, getting sidetracked here, we could let yield e; where e throws emit that error instead of failing. Breaking change, though.)

(Arguably it could also apply to an iterable iteration where the current getter throws.)

lukepighetti commented 3 years ago

There's a lot to tease out here for new features. One that comes to mind is throw* StreamException, but we don't have to dig into that here I don't think.

finally for onDone would be awesome. It's all upside imho. I like it so much I'm going to add it to the original post.

PlugFox commented 3 years ago

@lukepighetti check this sample)

https://dartpad.dev/1b73d1115f3c8de0ca70872f70ad9d95?null_safety=true

lukepighetti commented 3 years ago

What am I looking for?