What does 'yield' keyword do in flutter?
Asked Answered
N

4

117

What does the yield keyword actually do in Dart?

Novice answered 20/4, 2019 at 17:32 Comment(0)
P
169

yield adds a value to the output stream of the surrounding async* function. It's like return, but doesn't terminate the function.

See https://dart.dev/guides/language/language-tour#generators

Stream asynchronousNaturalsTo(n) async* {
  int k = 0;
  while (k < n) yield k++;
}

When the yield statement executes, it adds the result of evaluating its expression to the stream. It doesn’t necessarily suspend (though in the current implementations it does).

Paget answered 20/4, 2019 at 17:39 Comment(4)
It's like return, but doesn't terminate the function. What a perfect way to explain this without going into the weeds.. Thank you. That said, if you want to go into the weeds on this topic Tokenyet has a great answer below.Prague
Perfect, plus one, for short complete answer and comparisonGuncotton
One important thing to mention: In async* functions yield halts execution of current task and switches it to caller (await for loop). Not keeping it in mind might lead you into very weird execution stalls. Couple of gists to highlight potential problem: non-stalling example, stalling exampleHence
Last note is no longer present in the documentation, now it clearly says An async* function automatically pauses at a yield statement while the stream subscription is paused.Dykes
C
134

The accepted answer's link is broken, here is an official link about async* sync* yield* yield.

If you have some experiences with other languages, you might stuck at these keywords. Here are some tips for getting over keywords.

  1. async* sync* yield* yield are called generator functions. You might use these mostly in Bloc pattern.

  2. async* is also a async, you could use Asynchronous as usual.

  3. sync* cannot be used as sync, you will receive the error that noticed "The modifier sync must be followed by a star".

  4. yield and yield* can only be used with generator functions (async* sync*).

And there are four combinations.

  1. async* yield will return a Stream<dynamic>.
Stream<int> runToMax(int n) async* {
  int i = 0;
  while (i < n) {
    yield i;
    i++;
    await Future.delayed(Duration(seconds: 300));
  }
}
  1. async* yield* will call a function and return Stream<dynamic>.
Stream<int> countDownFrom(int n) async* {
  if (n > 0) {
    yield n;
    yield* countDownFrom(n - 1);
  }
}
  1. sync* yield will return a Iterable<dynamic>.
Iterable<int> genIterates(int max) sync* {
  var i = 0;
  while (i < max) {
    yield i;
    i++;
  }
}
  1. sync* yield* will call a function and return Iterable<dynamic>.
Iterable<int> countDownFrom(int n) sync* {
  if (n > 0) {
    yield n;
    yield* countDownFrom(n - 1);
  }
}

If there are any errors, please leave a comment to correct the answer.

Cogwheel answered 16/5, 2019 at 17:32 Comment(3)
I fixed the link in my answer.Paget
I think the correct answer for the yield* is, delegating to another generator rather than call a function. yield* simply delegates to the another generator which means the current generator stops, another generator takes the job until it stops producing. After that one stops producing values, the main generator resumes producing its own values.Cultivation
@Cultivation That is such a clear explanation that it should go into an answer, not just a comment.Danell
C
18

I think the correct answer for the yield* is, delegating to another generator rather than call a function. yield* simply delegates to the another generator which means the current generator stops, another generator takes the job until it stops producing. After that one stops producing values, the main generator resumes producing its own values.

Thanks @András Szepesházi for encouraging me to post this comment as an answer, hope it helps.

Cultivation answered 21/5, 2021 at 9:54 Comment(2)
Thanks, exactly what I needed. To add to your answer, yield* is useful for: A. refactor generator code by nesting multiple generators B. recursive generator.Instep
If your generator is recursive, you can improve its performance by using yield*Instep
C
3

The yield statement can be used only in generator's functions.
The generator's function generates data items in natural way (as calculated, received from outside, predefined values etc).
When next data item is ready then the yield statement send this item into data sequence which is essentially the generation result of the function.
The data sequence can be synchronous or asyncronous.
In Dart language the synchronous data sequence means the instance of Iterable.
The asynchronous data sequence means the instance of Stream.

P.S.
Generator functions can generate data items indefinitely until the function returns.
But unlike normal functions, the result (the data sequence) will be returned immediately after the function call and can be used immediately.
The end of the data sequence, in this case, can be reached only when generator function will be terminated (successfully or by failure).

Citrine answered 20/4, 2019 at 18:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.