Skip to content
AgileLogics
7 min read

Constructors

Prerequisites: Classes and objects

Dart has several kinds of constructors. You'll see all of them in real code, especially in Flutter.

Named parameters in constructors

class User {
  final String name;
  final String role;
  final bool active;

  User({required this.name, this.role = 'member', this.active = true});

  @override
  String toString() => 'User($name, $role, active: $active)';
}

void main() {
  print(User(name: 'Ada'));
  print(User(name: 'Linus', role: 'admin'));
}
User(Ada, member, active: true)
User(Linus, admin, active: true)

This is exactly how Flutter widgets are defined and created.

Named constructors

A class can have several constructors with different names:

class Temperature {
  final double celsius;

  Temperature(this.celsius);
  Temperature.fahrenheit(double f) : celsius = (f - 32) * 5 / 9;
  Temperature.freezing() : celsius = 0;
}

void main() {
  print(Temperature(25).celsius);
  print(Temperature.fahrenheit(212).celsius);
  print(Temperature.freezing().celsius);
}
25.0
100.0
0.0

The part after : is an initializer list — it sets final fields before the constructor body runs. You can also put assert checks there.

const constructors

If every field is final, a constructor can be const. Constant objects with the same values are created once and shared:

class Point {
  final int x;
  final int y;
  const Point(this.x, this.y);
}

void main() {
  const a = Point(1, 2);
  const b = Point(1, 2);
  print(identical(a, b));
}
true

Flutter relies on this: const Text('Hello') is built once and reused, which saves work when the screen redraws.

Factory constructors

A factory constructor doesn't have to create a new object — it can return a cached one, or pick a subclass:

class Logger {
  static final Map<String, Logger> _cache = {};
  final String name;

  Logger._internal(this.name);

  factory Logger(String name) {
    return _cache.putIfAbsent(name, () => Logger._internal(name));
  }
}

void main() {
  final a = Logger('network');
  final b = Logger('network');
  print(identical(a, b));
}
true

Logger._internal is a private named constructor (the underscore), so code in other files must go through the factory. Factories are also the usual place for fromJson constructors, covered in the JSON lesson.

Common mistakes

  • Trying to assign a final field inside the constructor body — too late. Use this.field parameters or the initializer list.