Quick Tip #5 — sync*, a taste of the future

How to build dynamic lists of widgets?

This is one of the most common issues faced by Flutter developers.

Indeed, the List literal is not easy to work with and creating a complex list can be a painful experience — be it conditionally adding a widget in a Column or concatenating a children argument with custom logic.

As such, it is not uncommon to find code that looks like this:

Do you have trouble reading this example? Don’t worry, me too.

This horror is due to a combination of facts:

  • Dart does not have a spread operator
  • Widgets do not allow null as a valid child
  • Widgets are supposed to be entirely immutable. So building the list in multiple steps doesn’t feel right.

These facts led to “Allow null values in child or children[] collections” be one of the most upvotes issues on Flutter’s GitHub.


And we’ve been heard!

While Flutter will still not allow null as a valid widget, it has been decided to fix these issues directly in Dart instead.

As such, two new languages features have been drafted and recently got flagged as “being implemented”:

With these two combined, our previous example becomes the following:

That’s much better!


But what can we do right now?

While new features are cool, there is no official release date. We can’t just pause our development until these are available. We need a temporary solution to this problem.

Fact is, these new syntaxes are nothing but a syntax sugar over sync* functions. As such, we can already use them by writing a sync* function ourselves!

With sync* functions, our example now becomes:

This example is not perfect, for sure. But it is infinitely better than our first attempt using List literal.

We have access to the spread operator through yield* and if /for too with their usual syntax combined toyield .

This is more robust as we’re not filtering null anymore, which could hide potential mistakes. And we’re not creating our list through mutation either, which is in accordance to the immutability principle of widgets.

This is also more flexible because we have the full power of a function; as opposed to the limited methods that List offer.


Conclusion:

The future is very promising, with spread operator and conditional addition to List literal.

Fortunately, we already have access to these features through a slightly less convenient syntax, using sync* functions.

We can start by using the sync* equivalent, and once these new features lands, easily convert to a cleaner syntax with no behavioral change.