19 const
and non-const
constructors
The difference between const
and non-const
constructors relates to when and how objects are created, and whether they can be compile-time constants.
19.1 const
Constructor
A const
constructor creates compile-time constants - objects that are fully determined at compile time and are immutable. Think of them as “frozen blueprints” that never change.
class Point {
final int x;
final int y;
// const constructor - all fields must be final
const Point(this.x, this.y);
}
void main() {
// These are compile-time constants
const point1 = Point(10, 20);
const point2 = Point(10, 20);
// Dart optimizes: point1 and point2 are the SAME object in memory
, point2)); // true
print(identical(point1}
19.2 Non-const
Constructor
A non-const
constructor creates objects at runtime. Each call creates a new instance, even with identical values.
class MutablePoint {
int x;
int y;
// Non-const constructor - can have mutable fields
this.x, this.y);
MutablePoint(}
void main() {
var point1 = MutablePoint(10, 20);
var point2 = MutablePoint(10, 20);
// These are different objects in memory
, point2)); // false
print(identical(point1
// You can modify them
.x = 30;
point1}
19.3 Key Differences
Here’s a visual representation of the differences:
const Constructor:
Compile time: Point(10, 20) → [Memory: Object A]
Runtime: const p1 = ... → Points to Object A
const p2 = ... → Points to Object A (same object!)
Non-const Constructor:
Runtime: var p1 = Point(10, 20) → [Memory: Object A]
var p2 = Point(10, 20) → [Memory: Object B] (different objects)
19.4 Rules for const
Constructors
All fields must be final
class ValidConstClass {
final String name;
final int age;
const ValidConstClass(this.name, this.age); // ✅ Valid
}
class InvalidConstClass {
String name; // Not final!
final int age;
// const InvalidConstClass(this.name, this.age); // ❌ Error!
}
All constructor parameters must be compile-time constants
class Person {
final String name;
final DateTime birthDate;
const Person(this.name, this.birthDate);
}
void main() {
// ✅ Valid - string literal is compile-time constant
const person1 = Person('Alice', DateTime(1990, 1, 1));
// ❌ Error - DateTime.now() is runtime value
// const person2 = Person('Bob', DateTime.now());
}
19.5 When to Use Each
Use const
constructor when:
- Immutable data structures - Configuration objects, mathematical points, colors
class AppConfig {
final String apiUrl;
final int timeout;
final bool debugMode;
const AppConfig({
this.apiUrl,
required this.timeout,
required this.debugMode,
required });
}
// Usage
const config = AppConfig(
: 'https://api.example.com',
apiUrl: 5000,
timeout: false,
debugMode );
- Flutter widgets - Most built-in Flutter widgets use const constructors
const Text('Hello World')
const Icon(Icons.home)
const SizedBox(width: 100, height: 50)
- Value objects - Objects that represent values rather than entities
class Money {
final double amount;
final String currency;
const Money(this.amount, this.currency);
}
const price = Money(29.99, 'USD');
Use non-const
constructor when:
- Mutable objects - Objects that need to change after creation
class Counter {
int value;
this.value);
Counter(
void increment() => value++;
}
- Objects with runtime dependencies - Database connections, HTTP clients
class ApiClient {
final String baseUrl;
late final Dio _dio;
this.baseUrl) {
ApiClient(= Dio(BaseOptions(baseUrl: baseUrl));
_dio }
}
- Objects that perform side effects - Logging, file operations
class Logger {
final String fileName;
this.fileName) {
Logger(// Side effect: create log file
_createLogFile();}
void _createLogFile() {
// File creation logic
}
}
19.6 Performance Considerations
const
constructors provide significant performance benefits:
- Memory efficiency: Identical const objects share the same memory location
- Build optimization: Flutter can skip rebuilding const widgets
- Compile-time optimization: Values are computed once at compile time
// Flutter example
class MyWidget extends StatelessWidget {
const MyWidget({Key? key}) : super(key: key);
@override
{
Widget build(BuildContext context) return Column(
: [
childrenconst Text('This widget is const'), // Won't rebuild unnecessarily
'This widget is not const'), // May rebuild
Text(,
]
);}
}
19.7 Quick Decision Guide
Ask yourself:
- Will this object ever change after creation? → If no, consider
const
- Are all the values known at compile time? → If yes, use
const
- Do I need to perform setup operations in the constructor? → If yes, use non-
const
- Is this a Flutter widget that won’t change? → Use
const
for performance
The general rule: Use const
when you can, use regular constructors when you must. Your Flutter apps will be more performant with proper const
usage!