Dart Core Optimization Series
Part 2: Compile-Time vs. Run-Time - The Power of const
Of course. After understanding Null Safety, we'll look at a small but very important difference in Dart that directly affects how the compiler optimizes your code: final vs. const.
Many developers new to Dart get confused between final and const because both are used to create variables that cannot be changed. However, they work at two completely different times.
1. final (A Run-time Constant)
What it means: "This variable can only be assigned a value one time. After it's assigned, it cannot be changed."
When the value is known: At run-time (when the code is executing).
Examples:
dart// The value of `DateTime.now()` is only known when the code runs. final finalTime = DateTime.now(); // `name` is given a value when the function is called at run-time. final String name;Performance:
finalmakes code safer by preventing changes, but it doesn't offer much optimization for the compiler because the value isn't known beforehand.
2. const (A Compile-time Constant)
What it means: "This variable is a constant at compile-time. Its value must be known when you are writing the code."
When the value is known: At compile-time (when the app is being built).
Examples:
dartconst appName = "My Awesome App"; const primaryColor = Color(0xFF0000FF); // ERROR: DateTime.now() is not a compile-time constant. // const compileTimeError = DateTime.now();
The Optimization "Magic" of const 🧐
When you declare an object as const, you give the compiler a superpower:
- Pre-calculation: The compiler can calculate or create the object just once during the build process.
- Canonicalization: The compiler ensures that for a given
constvalue, only one single instance exists in the entire application. Every place in your code that uses that constant will point to the same memory address.
Problematic Code (using final):
// Every time this function is called, a NEW instance of `Padding` is created.
Widget buildPadding() {
final padding = EdgeInsets.all(8.0);
// ...
}Optimized Code (using const):
// The compiler creates a single instance of `EdgeInsets.all(8.0)`
// and reuses it everywhere.
Widget buildPadding() {
const padding = EdgeInsets.all(8.0);
// ...
}The Result:
- No Memory Allocation: Using
constcompletely eliminates unnecessary memory allocation at run-time. - Higher Performance: It reduces the pressure on the Garbage Collector and helps Flutter rebuild widgets faster.
Conclusion:
- Golden Rule: "Always prefer
constoverfinalif the variable's value can be determined at compile-time." finalis for ensuring a variable is not reassigned.constis a powerful performance optimization tool that reduces memory allocation and allows the compiler to perform deeper optimizations.