Generators

Dart Generator is a unique function that allows us to produce a sequence of values. Generators return values on demand; it means the value is generated when we try to iterate over the iterators. Dart provides built-in support for two types of generator functions.

  • Synchronous Generators
  • Asynchronous Generators

Synchronous Generator

It returns an iterable object which carries value synchronously. The yield keyword is used along with marking the synchronous generator function body as sync* to generator values.

Let’s understand the following example of a synchronous generator.

Example –

main()  {  

    print("Dart Synchronous Generator Example.");  

    oddNumber(10).forEach(print);   

}  

    // syn* functions returns an iterable  

  

   Iterable<int> oddNumber(int num) sync* {  

    int k = num;  

    while(k >= 0) {  

         if(k%2 == 1) {  

            // 'yield' statement  

            yield k;  

  

                }  

k--;  

}  

}

Output

Dart Synchronous Generator Example.
9
7
5
3
1

Explanation:

In the above program, we declared an oddNumber(10) function with the foreach loop without its body. The foreach loop will iterate the function. Now, we created oddNumber(10) function as synchronous generator function.

In the function body, we initialized a new variable k, which assigns the argument n. Then, we applied while loop to iterate the function, and the loop body is iterated until the value of k is less than or equal to 0.

We did modulus operation on k to find the odd numbers from the generators. We used the yield statement, which suspends the function’s execution and returns the value at a time. It will return the value of each execution of the generator function. When the while loop’s condition becomes false, then the loop terminated and prints the odd numbers.

Asynchronous Generators

It returns a stream object which carries value asynchronously. The yield keyword is used along with marking the asynchronous generator function body as async* to generator values.

Let’s understand the following example –

Example –

main()  {  

    print("Dart Asynchronous Generator Example.");  

    asyncNaturalsTo(10).forEach(print);   

}  

    // async* functions returns an stream object  

  

   Stream<int> asyncNaturalsTo(int num) async* {  

    int k = 0;  

    while(k < num) {  

   

            // 'yield' statement  

            yield k++;  

  

                }  

k--;  

} 

    Output

    Dart Asynchronous Generator Example.
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    

    Explanation:

    The above code generated values asynchronously. The asyncNaturalsTo(int num) function returns a stream objects in each execution of function body. Here, the yield keyword behaved the same as the previous example; it stopped the execution of the function, returned the value, and resumed the execution for the next iteration. It will happen again and again until the function body is terminated.

    Let’s understand the following concepts related to the generator function.

    The yield Keyword

    The yield returns the single value to the sequence at a time but does not stop the execution of the generator function completely. It returns a value for each execution of the generator function.

    The sync* Keyword –

    The sync* keyword is used to declare the synchronize generator function. It returns the value when we try to iterator the value not when it was created. Let’s have a look at the following example –

    Example –

    void main() {  
    
      print('creating iterator');  
    
      Iterable<int> numbers = getNumbers(4);  // Here we are creating iterator  
    
      print('Iteration starts...');  
    
      for (int i in numbers) {  
    
        print('$i');        // Iterate over the iterator  
    
      }  
    
      print('end of main function');  
    
    }  
    
    Iterable<int> getNumbers(int n) sync* {            // define generator synchronously  
    
      print('generator started');  
    
      for (int i = 0; i < n; i++) {  
    
        yield i;  
    
      }  
    
      print('generator function ended');  
    
    }  

      Output

      creating iterator
      Iteration starts...
      generator started
      0
      1
      2
      3
      generator function ended
      end of main function
      

      Explanation –

      The above generator function generated the value when we iterate over the iterator.

      The async* Keyword

      The async keyword is used to declare the asynchronous generators. It returns the stream object. Let’s understand the following example –

      Example –

      void main() {  
      
        print('creating iterator');  
      
        Stream<int> numbers = getNumbers(4);  
      
        print('starting to listen...');  
      
        numbers.listen((int k) {  
      
          print('$k');  
      
        });  
      
        print('end of the main function');  
      
      }  
      
      Stream<int> getNumbers(int number) async* {   // declaring asynchronous generator function  
      
        print('waiting inside generator a 3 seconds :)');   
      
        await new Future.delayed(new Duration(seconds: 3)); //sleep 3s  
      
        print('started generating values...');  
      
        for (int i = 0; i < number; i++) {  
      
          await new Future.delayed(new Duration(seconds: 1)); //sleep 1s  
      
          yield i;  
      
        }  
      
        print('ended generating values...');  
      
      } 

        Output

        creating iterator
        starting to listen...
        end of the main function
        waiting inside generator a 3 seconds :)
        started generating values...
        0
        1
        2
        3
        ended generating values...
        

        Comments

        Leave a Reply

        Your email address will not be published. Required fields are marked *