prefer-const-constructors

Same as prefer_const_constructors in Dart lints

Group
Style
Path
lint/style/prefer-const-constructors
Default
Off, opt in
Origin
Dart lints
Rule
327 of 512

Prefers const when invoking a const constructor with constant arguments.

When a constructor is declared const and the invocation would be a valid constant expression (constant arguments the constructor accepts, set elements and map keys with primitive equality, no type parameters in type arguments), invoking it with const produces a canonicalized instance instead of allocating a new one. The rule flags such invocations outside a constant context (where const is already implied). It stays silent when the constructor cannot be resolved to a declaration known to be const, when an argument cannot be proven constant, for Object() (often used to create unique identity tokens), for constructors of deferred-imported classes, and for a generic class invoked without type arguments whose approximate context contains type parameters. As in the analyzer, assignments use their result type rather than their target type.

class A {
  const A();
}

final a = A();       // BAD
final b = const A(); // GOOD

Invalid

example.dartdart
class Point {
  const Point(this.x, this.y);
  const Point.origin()
      : x = 0,
        y = 0;

  final int x;
  final int y;
}

class Label {
  const Label(this.text, {this.point = const Point.origin()});

  final String text;
  final Point point;
}

class Box<T> {
  const Box(this.value);

  final T value;
}

const int limit = 10;

void use(Object value) {}

void constructors() {
  final a = Point(1, 2);
  final b = Point.origin();
  final c = new Point(3, 4);
  final d = new Point.origin();
  final e = Box<int>(limit);
  final f = Label('title', point: const Point(0, 1));
  use(Point(limit, -1));
  final List<Point> points = [Point(5, 6)];
  final Point g = .origin();
  print([a, b, c, d, e, f, points, g]);
}

enum Shade { dark, light }

class Swatch {
  const Swatch(this.value, {this.shade});
  const Swatch.named(this.value) : shade = null;
  const factory Swatch.redirect(Object? value) = Swatch;
  static const int base = 1;
  final Object? value;
  final Shade? shade;
}

class Generic<T> {
  const Generic(this.value);
  const Generic.named(this.value);
  final T value;
}

int top() => 0;

void evaluatedArguments() {
  const local = 2;
  print(Swatch(Shade.dark));
  print(Swatch(Swatch.base));
  print(Swatch(local));
  print(Generic<int>.named(1));
  print(Swatch.redirect(1));
  print(Swatch('a' 'b'));
  print(Swatch(#symbol));
  print(Swatch(int));
  print(Swatch(top));
  print(Swatch(Swatch.named));
  print(Swatch(Shade.values));
  print(Swatch(identical(1, 2)));
  print(Swatch([if (true) 1]));
  print(Swatch({Swatch(1): 1}));
  final generic = Generic(1);
  print(generic);
}

// The context type `Box<List<T>>` has no type parameter as a type argument
// of `Box` itself, so making it `const` changes nothing.
Box<List<T>> emptyBox<T>() => Box([]);
Use `const` with the constructor to improve performance.
28void constructors() {
29 final a = Point(1, 2);
Use `const` with the constructor to improve performance.
29 final a = Point(1, 2);
30 final b = Point.origin();
Use `const` with the constructor to improve performance.
30 final b = Point.origin();
31 final c = new Point(3, 4);
Use `const` with the constructor to improve performance.
31 final c = new Point(3, 4);
32 final d = new Point.origin();
Use `const` with the constructor to improve performance.
32 final d = new Point.origin();
33 final e = Box<int>(limit);
Use `const` with the constructor to improve performance.
33 final e = Box<int>(limit);
34 final f = Label('title', point: const Point(0, 1));
Use `const` with the constructor to improve performance.
34 final f = Label('title', point: const Point(0, 1));
35 use(Point(limit, -1));
Use `const` with the constructor to improve performance.
35 use(Point(limit, -1));
36 final List<Point> points = [Point(5, 6)];
Use `const` with the constructor to improve performance.
36 final List<Point> points = [Point(5, 6)];
37 final Point g = .origin();
Use `const` with the constructor to improve performance.
61 const local = 2;
62 print(Swatch(Shade.dark));
Use `const` with the constructor to improve performance.
62 print(Swatch(Shade.dark));
63 print(Swatch(Swatch.base));
Use `const` with the constructor to improve performance.
63 print(Swatch(Swatch.base));
64 print(Swatch(local));
Use `const` with the constructor to improve performance.
64 print(Swatch(local));
65 print(Generic<int>.named(1));
Use `const` with the constructor to improve performance.
65 print(Generic<int>.named(1));
66 print(Swatch.redirect(1));
Use `const` with the constructor to improve performance.
66 print(Swatch.redirect(1));
67 print(Swatch('a' 'b'));
Use `const` with the constructor to improve performance.
67 print(Swatch('a' 'b'));
68 print(Swatch(#symbol));
Use `const` with the constructor to improve performance.
68 print(Swatch(#symbol));
69 print(Swatch(int));
Use `const` with the constructor to improve performance.
69 print(Swatch(int));
70 print(Swatch(top));
Use `const` with the constructor to improve performance.
70 print(Swatch(top));
71 print(Swatch(Swatch.named));
Use `const` with the constructor to improve performance.
71 print(Swatch(Swatch.named));
72 print(Swatch(Shade.values));
Use `const` with the constructor to improve performance.
72 print(Swatch(Shade.values));
73 print(Swatch(identical(1, 2)));
Use `const` with the constructor to improve performance.
73 print(Swatch(identical(1, 2)));
74 print(Swatch([if (true) 1]));
Use `const` with the constructor to improve performance.
74 print(Swatch([if (true) 1]));
75 print(Swatch({Swatch(1): 1}));
Use `const` with the constructor to improve performance.
74 print(Swatch([if (true) 1]));
75 print(Swatch({Swatch(1): 1}));
Use `const` with the constructor to improve performance.
75 print(Swatch({Swatch(1): 1}));
76 final generic = Generic(1);
Use `const` with the constructor to improve performance.
81// of `Box` itself, so making it `const` changes nothing.
82Box<List<T>> emptyBox<T>() => Box([]);

Valid

example.dartdart
class Point {
  const Point(this.x, this.y);
  const Point.origin()
      : x = 0,
        y = 0;

  final int x;
  final int y;
}

class Mutable {
  Mutable(this.value);

  int value;
}

class Box<T> {
  const Box(this.value);

  final T value;
}

void use(Object value) {}

Box<T> wrap<T>(T value) => Box<T>(value);

void constructors(int x) {
  const a = Point(1, 2);
  final b = const Point.origin();
  final c = Point(x, 2);
  final d = Mutable(1);
  final e = Object();
  final f = const [Point(1, 2), Point.origin()];
  final g = Unknown(1);
  use(Point(x, x));
  final Point h = const .origin();
  print([a, b, c, d, e, f, g, h]);
}

class Holder {
  const Holder([this.point = const Point(0, 0)]);

  final Point point;
}

@Deprecated('use Point.origin')
const origin = Point(0, 0);

class Keyed {
  const Keyed();
  @override
  bool operator ==(Object other) => other is Keyed;
  @override
  int get hashCode => 0;
}

class Wrapper {
  const Wrapper(this.value, {required this.flag}) : assert(value != null);
  final Object? value;
  final bool flag;
}

class Pair<T> {
  const Pair(this.first);
  final T first;
}

class Notify<T> {
  const Notify();
  void call(Pair<T> pair) {}
}

void notConstant(Notify<int> notify, Object? unknown) {
  print(Wrapper({1.5: 1}, flag: true));
  // Only the key itself can be const: `Keyed` overrides `==`.
  print(Wrapper({const Keyed(): 1}, flag: true));
  print(Wrapper(null, flag: true));
}

class Typed<T> {
  Pair<T> make() => Pair(1 as T);
  void send(void Function(Pair<T>) sink) => sink(Pair(null as T));
}

void constantPatterns(Object v) {
  switch (v) {
    case const (Point(1, 2)):
      break;
    default:
      break;
  }
  if (v case const (Point.origin())) {
    print(v);
  }
}

Configure prefer-const-constructors

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "prefer-const-constructors": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/style/prefer-const-constructors: <reason>