skip navigation
skip mega-menu
Flutter Macros Wave Goodbye to Boilerplate | Foresight Mobile

Welcome to the future of Flutter development! Imagine a world where the tedious task of writing boilerplate code is a thing of the past. Say hello to Dart Macros – your new secret weapon for supercharging productivity. These powerful runtime code generation tools work their magic behind the scenes, seamlessly reducing boilerplate and eliminating the need for cumbersome secondary tools. With Flutter macros, you can focus on crafting beautiful, high-performance apps while the macros handle the repetitive tasks, making your development process faster and more efficient than ever before. Get ready to unlock a new level of coding freedom and efficiency with Flutter macros!

So, what are macros?

A Dart macro is a customisable code snippet that takes other code as input and processes it in real-time to create, modify, or add new elements. Macros offer a reusable way to handle repetitive tasks and patterns, especially when dealing with the need to iterate over the fields of a class. Right now there’s one macro ready to go: JsonEncodable. As the name suggests, JsonEncodable generates the tedious fromJson and toJson methods for you.

Macros don’t require anything extra to run, just add the appropriate annotation that you need to your code and observe as the boilerplate code is generated in real time! With them, code is not written to the disk, so say goodbye to the part keyword. Macros directly augment the existing class.

What problem are they solving

Macros, as a static metaprogramming tool, provide an alternative to runtime code generation solutions (such as build_runner, json_serializable). Macros eliminate the need for a secondary tool, being integrated into Dart language, executing automatically in the background by Dart tools with every keystroke of your keyboard

  • No extra steps: Macros build your code in real-time as you write.
  • No performance hit: All the code generation happens directly in the compiler.
  • Clean and organised: No extra files cluttering up your project.
  • Clear error messages: Custom diagnostics appear right in your IDE, just like regular compiler messages.

Examples

Let’s compare 3 different code snippets, first without any code gen, second with Freezed and then third with macros

No Code Generation

Image Caption

Just typing this part out took a lot longer than it should for such a generic boilerplate. Obviously this is not even the whole class, it’s still missing the hashCode, == operator and possibly the toString overrides, and then do this for every (or at least most) model classes, and it turns out you’ve spent a lot of time on boilerplate code that is a lot of the time - error prone.

Now let’s look at Freezed

This looks a lot less error prone than manually writing the functions, but now you’ve got 2 new files that you need to work around, push to the project github or set up .gitignore. A lot less work than with manual writing, but still there are some parts of these files that could be considered as boilerplate.

Now let’s check it with macros

And that’s it! No other code needed to make this work. While you are typing the last semicolon the code is already generated and ready to be used. After writing this class we can go to some other file, and be able to do things like this:

Macros help you focus on the important stuff—the core logic of your product—and free you from the time-consuming, boring tasks that are essential but often get in the way.

It’s experimental - how to try it out

Set up the environment:

  1. Switch to the Dart dev channel or flutter master channel
  2. Run dart –version to make sure you have Dart version `3.5.0-152` or later
  3. Edit the SDK constraint in your pubspec to require Dart version: sdk: ^3.5.0-152.
  4. Add the package json to dependencies: dart pub add json.
  5. Enable the experiment in your package's analysis_options.yaml file. file at the root of your project:

  1. Import the package to the file that you’re planning to use import 'package:json/json.dart';
  1. Run the project with the experimental flag dart run --enable-experiment=macros bin/my_app.dart

Example of how to create custom macros

Your first custom macro should have two key segments, the macro keyword and an interface which determines for which interface the macro is determined. You can find the list of existing interfaces here.

For example, a macro that is applicable to enums, and adds new declarations to the enum, would implement the EnumDefinitionMacro interface:

With your custom macro created, you are ready to add it to a declaration, like below:

The Important thing to keep in mind is that at a high-level macros are using builders methods to combine properties of your declaration with identifiers on those properties, gathered through introspection of the codebase

Stable release timeline

The release of macros to stable is, as of the time of writing, unknown. A specific date has not yet been set due to the fact that macros work by deeply introspecting the codebase in which they’re applied. The general target for the release of JsonEncodable macro is projected to be until the end of 2024, and the stable release of the full functionality, including creating custom macros, for early-to-mid 2025.

FAQ

What is augmentation in dart?

Augmentation via the ‘augment’ keyword is the next step of evolution of the part keyword and part files, just without the extra syntax that makes your classes less clean. Augmentation allows defining class functions outside of the main class file.

For example we have this main class Person:

Now with the base class set, we can create our own json serialisation methods in a different part of the project, like this:

And after adding the import below, you will be good to go!

Why migrate from build_runner/freezed to macros? 

To improve the developer experience, of course! There is nothing wrong with these packages, they do the job perfectly, but with macros we make code cleaner by removing the _$ syntax needed for the packages mentioned above, as well as reduce the amount of workload on the developer to manage gitignored files or on peer review scroll endlessly over generated files to get to the crux of the pull request.

Explore jobs at Foresight Mobile

Mobile Software Engineer - Flutter, iOS, Android - Foresight Mobile
Stockport

Based in Manchester, Foresight Mobile are leading mobile app developers. We work collaboratively with founders, agencies, and consumers to design and develop exceptional digital experiences across iOS, Android, and the Web. Our team of expert UK app developers leverage the power of Google's Flutter framework to deliver cutting-edge apps that are not only visually stunning and high-performing but also boast rapid development times and exceptional return on investment.With over 21 years’ experience in the mobile app development industry working across a range of brands including EA, Body Building.com, Bandwidth and Levi Strauss, we can bring your app ideas to fruition. At every stage of the product lifecycle, we're here to provide the guidance and experience necessary to make an engaging product that's fit for market with measurable success.By leveraging our Flutter app development services, we deliver native experiences to your users at a lower cost to traditional native mobile development. The same application can also be published to the Web, targeting all major platforms with the same codebase.OUR DEVELOPMENT SERVICESMobile SDK and integration development for Flutter, React Native, iOS and AndroidCross-Platform iOS, Android app and Web app development with Google's revolutionary Flutter frameworkCross-Platform iOS and Android App development in React NativeMobile App Support and MaintenanceNative iOS and Android developmentTECH SUPPORTFractional CTO-as-a-service to businessesMVP Development and PrototypingTech EvaluationOutsourced Team ManagementPRODUCT DESIGNUser ExperienceClickable PrototypesMobile and Web DesignLogos and Branding

Foresight Mobile

Subscribe to our newsletter

Sign up here