-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Unexpected Behavior with Nested Async Generators #44616
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I actually think it should work. I'm guessing that the |
Yeah, adding a delay of Duration.zero between the yield statements of the nested generator makes the behavior consistent. Is this a bug then? If so, I’m happy to try to open a pull request to fix it. |
I think it's a bug, but I'm not absolutely sure we have specified The behavior of If you have an easy fix, do feel free to upload a PR. If it's complicated, we'll probably have to coordinate it so all the platforms behave the same way. I'll look into the spec. |
@lrhn have you had a chance to look into this? I would love to help get this fixed as it’s a pretty high priority for me but would need some guidance on how best to proceed. It looks like the issue might be here sdk/sdk/lib/_internal/vm/lib/async_patch.dart Line 136 in d10d17c
|
I've been reading the specification, and it's ... remarkably vague on everything. I'm working on a rewording. The The individual events should not be delayed, though. |
@lrhn thanks for the update! Let me know if there's anything I can do to help 👍 |
I'm attempting a fix: https://dart-review.googlesource.com/c/sdk/+/187000 Have to make sure the changed timing doesn't break people (too much), otherwise we might be stuck with the current behavior for a while. |
I've been running some internal tests, and the change does break a few tests. Not many, hopefully only a few root causes and if very lucky, it's a problem in the tests, not the real code. It's still code I'm not at all familiar with, so it might take some time to figure out. |
@lrhn thanks for the update. Do you have any sense of how difficult addressing the test failures will be? I just want to know if I should start considering alternative approaches as opposed to waiting for a fix. Thanks! |
I'd probably consider alternative approaches. Release cycles are long, and I'm not sure when this will make it (if it will, which I still hope). |
@felangel Do you have a workaround approach you commonly deploy in situations where this bug arises, or any other tips? I've been doing something along the lines of Stream<int> _increment() async* {
var newState = state;
newState = state + 1;
yield newState;
// ...
newState = state + 1;
yield newState;
} But I'd love to know if there's a cleaner way of doing this. Or the bug gets fixed. That'd be cool, too 👀 |
I generally do something like: Stream<int> mapEventToState(CounterEvent event) async* {
switch (event) {
case CounterEvent.increment:
yield* _mapIncrementToState(state);
break;
}
}
Stream<int> _mapIncrementToState(int state) async* {
yield state + 1;
yield state + 2;
} But yeah I was hoping this bug would be fixed. I'm currently playing around with alternative APIs which don't rely on nested generators to avoid this bug so I'll keep you posted 👍 |
Problematic without external dependencies https://dartpad.dev/8fe1bb47b6b5a6a496ced110f426c3a6 //@dart=2.13
typedef State = int;
/// Choose between generators
final stateGenerator = bad; // good;
// Listen generator, update and print current state
void main() => stateGenerator().listen((value) => print(state = value));
/// Current state +
State _state = 0;
set state(State value) {
print('* set $value');
_state = value;
}
State get state {
print('* get $_state');
return _state;
}
/// Current state -
/// Working properly generator
Stream<State> good() async* {
yield state + 1;
yield state + 1;
}
/// Not working properly inline generator
Stream<State> bad() async* {
Stream<State> _inline() async* {
yield state + 1;
yield state + 1;
}
yield* _inline();
} |
Workaround (if someone need quickfix in current project):Stream<State> mapEventToState(Event _) async* {
Stream<State> _inline() async* {
yield state + 1;
yield state + 1;
}
// Problem:
//yield* _inline();
// Workaround:
yield* _inline().asyncMap<State>(
(i) => Future<State>.microtask(() => i),
);
} |
Trouble:Stream<int> mapEventToState(CounterEvent event) async* {
switch (event) {
case CounterEvent.increment:
yield* _mapIncrementToState(state);
break;
}
}
Stream<int> _mapIncrementToState(int state) async* {
yield state + 1;
yield state + 2;
} Solve:Stream<int> mapEventToState(CounterEvent event) {
switch (event) {
case CounterEvent.increment:
return _mapIncrementToState(state);
}
}
Stream<int> _mapIncrementToState(int state) async* {
yield state + 1;
yield state + 2;
} |
I guess, I have noticed the same issue with a slightly different code: I am using a single state and I am updating it with I get it only do update the UI by chaining this to
|
Any news are welcome |
Having looked at |
😶 |
Any news about? Or we going to celebrate issue second birthday in a 8 weeks? |
Has this issue been silently fixed in dart version If I execute the original example on a fresh install of dart version
My
If I downgrade to dart
I stumbled over this while migrate an app to flutter |
Uh oh!
There was an error while loading. Please reload this page.
Dart core libraries ("dart:async")
dart --version
):Dart SDK version: 2.12.0-133.2.beta (beta) (Tue Dec 15 09:55:09 2020 +0100) on "macos_x64"
MacOSX
Reproduction Sample
Reproduction Steps
Expectations
I would expect that yielding inline would exhibit the same behavior as using
yield*
with a nested async generator.The text was updated successfully, but these errors were encountered: