flypenguin
flypenguin

Reputation: 735

How do these function return values work in Dart?

the official Bloc documentation gives this code snippet:

Stream<int> countStream(int max) async* {
    for (int i = 0; i < max; i++) {
        yield i;
    }
}

This looks very simple to me, until I realize that the function does not return anything (no returnstatement), but yields all the time (which is to me - coming from python - not the same as a return statement).

There's also this example, which is even more clear:

Future<int> sumStream(Stream<int> stream) async {
    int sum = 0;
    await for (int value in stream) {
        sum += value;
    }
    return sum;
}

Here there's an int returned explicitly, but if I read this correctly the function definition should return a Future<int>type:

Future<int> sumStream(Stream<int> stream) async { //...

Now, how does this work? I'm a bit confused here.

Thanks in advance! Axel.

Upvotes: 2

Views: 291

Answers (2)

mezoni
mezoni

Reputation: 11200

This looks very simple to me, until I realize that the function does not return anything (no return statement)

First of all, this function returns Stream<int> result value as specified in function declartion. This function often called as the generator function.

Stream<int> countStream(int max) async*

The function body code (generator) will generate the int values and yield these generated values to the initially returned Stream<int> stream.

The statement yield means in this case the following logic of work:
Add a value to Stream<int> controller and return to the next statement in the body of the function that follows that statement yield.

Something like this:

import 'dart:async';

Future<void> main() async {
  await for (final i in countStream(5)) {
    print(i);
  }
}

Stream<int> countStream(int max) {
  int i;
  final _ctl$ = StreamController<int>();
  void Function(int) _switchState$;
  _switchState$ = (int _state$) {
    while (true) {
      switch (_state$) {
        case 0:
          // for (int i = 0;
          i = 0;
          _state$ = 1;
          break;
        case 1:
          // i < max;
          if (i < max) {
            _state$ = 2;
          } else {
            return;
          }
          break;
        case 2:
          // yield i;
          _ctl$.add(i);
          Timer.run(() => _switchState$(3));
          return;
        case 3:
          // i++
          i++;
          _state$ = 1;
          break;
      }
    }
  };

  Timer.run(() => _switchState$(0));
  return _ctl$.stream;
}

Result:

0
1
2
3
4

Upvotes: 2

pirela
pirela

Reputation: 553

For your first example, countStream is a Stream of integer designed with an async*. (take care of the star)
In this stream definition, Yield emit a new integer on the stream flow (of integer as said by stream < int > .
If you consume the stream, you will get 0,1,2,3,4,...,max-1

In the second snippet, read it as : sumStream is a Future that must return an int.
More generally, A Future < T > instance produces a value of type T.
sumStream will consume a stream (given in parameter) and as long as this stream has values, sum them and return the last sum when finished. Sum is an integer : it's ok with Future definition.

Using both, you can have :

> void main() async  {   
   print(await sumStream(countStream(5)));   
}

result : 10 (0+1+2+3+4)

As sumStream is a Future, main can wait for asynchronous execution: it declares its intention to use async function (async declaration), then it can use await to stop its own execution until sumStream returns.

Another way if you leave main without async is to add a .then clause to the Future:

void main()  {
  sumStream(countStream(5)).then((x)=>print(x));
  print("after sumStream");
}

Result :
after sumStream
10

As you can see main pass over sumStream it has started but which is not finished and print("after sumStream") first.
Then the main finished, but Dart knows there is still async job running and it will wait until all is done, so we can see the result, but once Future sumStream is finished.

HTH

Upvotes: 3

Related Questions