prefer-final-locals

Same as prefer_final_locals in Dart lints

Group
Style
Path
lint/style/prefer-final-locals
Default
On (recommended)
Origin
Dart lints
Rule
356 of 512
recommended

Prefer final for local variable declarations that are never reassigned.

A local declared with var (or just a type) that is initialized and never written again reads better as final: the reader learns at the declaration that the value does not change. Writes are tracked lexically across the whole enclosing body, including closures, so a variable assigned anywhere in its scope is left alone. Pattern declarations (var (a, b) = r;), variables bound by for (var (a, b) in pairs), and variable patterns in if-case clauses, switch statement cases, and switch expression arms are covered too. Like the analyzer, patterns outside any function body (in top-level variable and field initializers) are not reported. Local diagnostics use the declaration keyword or type span, excluding matching words in documentation and annotation arguments.

void f() {
  var count = items.length; // flagged
  final total = sum(items); // ok
}

Invalid

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

int compute(List<int> items) {
  var total = items.length;
  int doubled = total * 2;
  var a = 1, b = 2;
  late var lazy = a + b;
  return doubled + lazy;
}

void patterns((int, int) pair, Object o, List<(int, String)> rows) {
  var (left, right) = pair;
  print(left + right);
  for (var (n, s) in rows) {
    print('$n$s');
  }
  if (o case int value) {
    print(value);
  }
  switch (o) {
    case String text:
      print(text);
    case Point(x: var px):
      print(px);
  }
}

void closures() {
  var shadowed = 1;
  void inner(int shadowed) {
    shadowed = 2;
    print(shadowed);
  }

  inner(shadowed);
  for (var i = 0; i < 3;) {
    break;
  }
}

String switchArms(Object o, (int, String?) pair) {
  final label = switch (o) {
    int v => '$v',
    var other => '$other',
  };
  return switch (pair) {
    (_, var text?) => text + label,
    _ => label,
  };
}
Local variables should be `final`.
7int compute(List<int> items) {
8 var total = items.length;
Local variables should be `final`.
8 var total = items.length;
9 int doubled = total * 2;
Local variables should be `final`.
9 int doubled = total * 2;
10 var a = 1, b = 2;
Local variables should be `final`.
10 var a = 1, b = 2;
11 late var lazy = a + b;
Local variables should be `final`.
15void patterns((int, int) pair, Object o, List<(int, String)> rows) {
16 var (left, right) = pair;
Local variables should be `final`.
17 print(left + right);
18 for (var (n, s) in rows) {
Local variables should be `final`.
17 print(left + right);
18 for (var (n, s) in rows) {
Local variables should be `final`.
20 }
21 if (o case int value) {
Local variables should be `final`.
24 switch (o) {
25 case String text:
Local variables should be `final`.
26 print(text);
27 case Point(x: var px):
Local variables should be `final`.
32void closures() {
33 var shadowed = 1;
Local variables should be `final`.
39 inner(shadowed);
40 for (var i = 0; i < 3;) {
Local variables should be `final`.
46 final label = switch (o) {
47 int v => '$v',
Local variables should be `final`.
47 int v => '$v',
48 var other => '$other',
Local variables should be `final`.
50 return switch (pair) {
51 (_, var text?) => text + label,

Valid

example.dartdart
int compute(List<int> items) {
  final total = items.length;
  const limit = 10;
  var count = 0;
  count += total;
  var index = 0;
  index++;
  int? lazy;
  lazy = count;
  var a = 1, b = 2;
  b = a;
  for (var i = 0; i < limit; i++) {
    count += i;
  }
  var _ = compute(items);
  return count + (lazy ?? 0) + index + b;
}

void patterns((int, int) pair, Object o, List<(int, String)> rows) {
  final (left, right) = pair;
  var (first, second) = pair;
  first = second;
  var (_, _) = pair;
  print(left + right + first);
  for (final (n, s) in rows) {
    print('$n$s');
  }
  for (var (n, s) in rows) {
    n++;
    print('$n$s');
  }
  if (o case final int value) {
    print(value);
  }
  if (o case int value) {
    value = 2;
    print(value);
  }
  final label = switch (o) {
    final int v => '$v',
    _ => '',
  };
  print(label);
}

void closures() {
  var captured = 1;
  void inner() {
    captured = 2;
  }

  inner();
  print(captured);
  var swapped = 1;
  var other = 2;
  (swapped, other) = (other, swapped);
  print(swapped + other);
  var loop = 0;
  for (loop in [1, 2, 3]) {
    print(loop);
  }
}

// Patterns outside any function body are not reported.
final topLevelLabel = switch (Object()) {
  int v => '$v',
  _ => '',
};

Configure prefer-final-locals

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "prefer-final-locals": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/style/prefer-final-locals: <reason>