[Part 1] Code generation in Dart: the basics

Have you ever wonder what makes a software programmer a great software programmer? Think about it for a minute. The answers could be pretty much endless, and depending on who you ask, you will get different responses… but if you ask me, being a lazy programmer will be my answer ;)

Doing more with less is key to progress. No one likes repeating the same task over and over again. It is tedious, boring, and not creative at all. Humans are really bad at this. We often make mistakes when doing something repetitive. However, guess who is really good and effective doing all these tasks that humans do not enjoy? I hope we are thinking the same: COMPUTERS!

https://yougottobekidding.wordpress.com/2012/02/18/geeks-and-repetitive-tasks/

Code generation is key nowadays to get the job done, in the shortest amount of time possible. The idea is simple: for all those tedious tasks that you do over and over again in your code base, you can find the pattern behind, create a generator tool, run it and see the magic happen!

In the Android world, these tools are part of the bread and butter of every developer: Retrofit, Dagger, Room… but what about Dart? And more important, what do we need to build our own tools?

Dart and code generation: tools available

In order to create tools that auto generate code, you will probably need to use these two packages:

source_gen

This package provides an friendly API to auto generate code. It is a better abstraction of some low level Dart packages, such as analyzer or build. While it is not mandatory to use, definitely it will save you a lot of headaches.

source_gen provides two abstract generator classes, that can be considered visitor classes:

  • Generator: when extending this class, every single element of your code will be visited, so you have full control over what to do with the node/element being visitied.
  • GeneratorForAnnotation: similar to a simple Generator, but in this case you will also give it an “annotation”, so every node annotated with the given annotation will be visited, and the rest of nodes that are not annotated will be ignored.

Part of the job will be also configuring the Builder that will wrap your generator. You have these options:

  • If you want to write a partial piece of code, then using a SharedPartBuilder is your best option. “part” allows you to split a library into multiple Dart files. This will produce a file with the extension .g.dart .
  • You can use PartBuilder if you still want to use a part approach, but control the extension file, such as .my_file.dart .
  • If you just want to write a standalone library that can be imported, use a LibraryBuilder .

We will see a practical example in the Part 2 of these series of articles.

build_runner

This tool allow us to run our generators during the development phase. It can be invoked from the command line in this fashion:

pub run build_runner <command>

where <command> can be:

  • build: run a single build and exit
  • watch: runs a daemon that will run on file changes and rebuilds if necessary
  • serve: similar to watch, but also runs as a development server
  • test: for testing purposes

In order to make it work in harmony with source_gen, we will need to configure a build.yaml file where we specify the different details of our generator configuration.

Who uses code generation in Dart?

When looking for inspiration and libraries that use code generation, you will immediately see some of the most famous packages available:

In the next article…

Now that we know the tools that we have available to auto generate code, in the next article of this series we will focus on a tiny project where we will use annotations and code generation keep track of all the TODOs in our application.


You can follow me on https://twitter.com/jcocaramos and see more code here on my public Github https://github.com/jorgecoca