Classes and constructors

Dart · Essentials · 14 min

Everything in Flutter is a class, and widget classes rely on const and named constructors.

A class declares fields, constructors and methods. Every non-nullable field must be initialized before the constructor body runs.

Constructor forms:

  • Initializing formals: Point(this.x, this.y); assigns parameters directly to fields. Named: Person({required this.name, this.age = 0});.
  • Initializer list after : runs before the body: Rect(double w) : width = w, height = w * 2;. It can also hold asserts.
  • Named constructors give alternatives: Point.origin() : x = 0, y = 0;.
  • Redirecting: Point.onX(double x) : this(x, 0);.
  • const constructors for immutable classes (all fields final): const Point(this.x, this.y);. Calling with const Point(1, 2) creates a canonical compile-time constant.
  • factory constructors may return an existing instance or a subtype, e.g. from a cache or fromJson.

Getters and setters look like fields: double get area => width * height;. Fields are implicitly given getters (and setters if not final), so you can later replace a field with a getter without changing callers.

Privacy is per library (file), not per class: names starting with _ are private to the file.

Override toString, == and hashCode for value-like classes; otherwise == compares identity. Dart has no new requirement — just call Point(1, 2).

Example

class Point {
  final double x;
  final double y;
  const Point(this.x, this.y);
  const Point.origin() : this(0, 0);
  factory Point.fromJson(Map<String, dynamic> json) =>
      Point((json['x'] as num).toDouble(), (json['y'] as num).toDouble());
  double get lengthSquared => x * x + y * y;   // a getter
  Point operator +(Point o) => Point(x + o.x, y + o.y);

  @override
  bool operator ==(Object other) => other is Point && other.x == x && other.y == y;
  @override
  int get hashCode => Object.hash(x, y);
  @override
  String toString() => 'Point($x, $y)';
}

void main() {
  final p = Point(3, 4) + Point.fromJson({'x': 1, 'y': 0});
  print(p);                                    // Point(4.0, 4.0)
  print(p.lengthSquared);                      // 32.0
  print(Point(1, 1) == Point(1, 1));           // true (custom ==)
  print(identical(const Point.origin(), const Point(0, 0)));  // true
}

Remember

  • this.x parameters and initializer lists set final fields
  • Named, const and factory constructors cover most creation needs
  • _name is private to the library (file), not the class

Watch out for

  • Overriding == without also overriding hashCode, which breaks Sets and Maps.

Check yourself

  1. Where is a member named `_cache` visible?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: dart.dev/language/constructors

Classes and constructors · Dart · Topolearn