If you’re a programmer, regardless of your domain, you probably write a lot of code that deals with sequences of values. In most cases, a data structure like an array is the best tool for these jobs. You can simply write out every value your program will need to process as a constant before the program runs. Your program can then iterate through the data structure at runtime and pull out new values one at a time.

const languages = const [
  "English",
  "Spanish",
  "Mandarin",
  "German",
  "Hindi"
];

void main() {
  for (var language in languages) {
    print("Building database for $language.");
    // ...
  }
}

When constants won’t cut it

However, predefined data structures aren’t ideal for all situations where you need to iterate a list of values. In some cases, they won’t work at all. Sometimes it’s not possible to know what all the values in your list are going to be before the program runs. If your sequence is particularly lengthy, your computer might not have enough memory to hold the entire list at one time. Even if it’s possible to write out all the values your program will need by hand, doing so is often painful, ugly, or impractical.

const powersOfTwo = const [
  1,
  2,
  4,
  8,
  16,
  32,
  64,
  128,
  256,
  512,
  1024,
  2048,
  4096,
  8192,
  16384,
  32768,
  65536,
  131072,
  262144,
  524288,
  1048576
];

void main() {
  for (var powerOfTwo in powersOfTwo) {
    print("Allocating memory chunk of size $powerOfTwo.");
    // ...
  }
}

That list only goes up to 220. As it is, the list is unwieldy. Every time I type a new value, there’s a good chance that I’m going to make a typo and introduce a bug. What if my program needs to go all the way up to 232? That’s going to be a mess.

Cleaner with a generator

Don’t despair! Dart offers a language level feature that allows us to express our sequence much more concisely, and without the susceptibility to typos. Of course I’m talking about generators. Generators let you declare a function that you can iterate through, as if it were a regular List.

Iterable<int> powersOfTwoTo(int n) sync* {
  for (var exponent = 0; exponent <= n; exponent++) {
    yield pow(2, exponent);
  }
}

void main() {
  for (var powerOfTwo in powersOfTwoTo(32)) {
    print("Allocating memory chunk of size $powerOfTwo.");
    // ...
  }
}

Note that in the above example I could have used a bitshift operator yield 1 << exponent; to produce the same results. I’m opting for the pow function because it makes the intent of my code clearer.

What’s going on here?

You might be a little perplexed by the yield keyword in there. What does that mean? A yield statement is a lot like a return statement, except that Dart saves the state of all variables in the generator function. When the generator is resumed, execution continues right where it left off, with the same variable values it had before yielding.

Is it possible to produce the same sequence of values programmatically without invoking a generator function? Sure–especially for an example as simple as this one, it’s easy enough to write plain old imperative code that will produce values on the fly. Just because generators are more fun to write doesn’t mean that they’re automatically the best option. You should always ask yourself whether a generator function really is the cleanest, clearest way to express your code. Sometimes it is, and when it is, Dart’s efficient language level support really shines.

Example code for practice

Here’s an example I threw together that one could imagine in a web browser or a game engine. You’re trying to draw a horizontal gradient, and you need to calculate the blended color values at a given number of equally-spaced points from left to right. A generator may not be the most efficient way to compute these values, but I wanted to provide an example of a generator that produced something more sophisticated than plain ints. Try playing around with the code! Alter the leftColor and rightColor inputs, or change the number of blends. Maybe you can even build a generator of your own that yields an even more interesting series of objects.