prefer-for-in

Group
Style
Path
lint/style/prefer-for-in
Default
Off, opt in
Origin
Falcon
Rule
360 of 512

Flags zero-based, unit-step index loops over a syntactically known list.

A for-in loop expresses element traversal directly; use .indexed when the index is also needed. Matches a single local initialized to 0, a strict index < items.length bound, and index++, ++index, or index += 1. The collection must be a local or parameter explicitly typed List, or a local with an inferred type initialized with a list literal. Other types, fields, and computed receivers are skipped because syntax alone cannot establish iterability. Files with unprefixed imports, library parts, or a possible local declaration shadowing List are skipped rather than guessing the collection's identity.

Body writes to the index, collection rebinding, element writes, collection escapes or method calls, closures, cascades, and suspension are excluded. Collection references in the body must be direct items[index] reads. Collection and index references must resolve to the original declarations; shadowed bindings cannot stand in for either loop variable. This is a syntactic recommendation, not an automatic rewrite: indirect mutation through aliases or opaque function calls is not analyzed.

Invalid

example.dartdart
void canonical(List<int> items) {
  for (var i = 0; i < items.length; i++) {
    print(items[i]);
  }
  for (int index = 0; index < items.length; ++index) {
    print(items[index]);
  }
  for (var i = 0; i < items.length; i += 1) {
    print('$i: ${items[i]}');
  }
  for (var i = (0); (i) < (items.length); i++)
    print(items[i]);
  for (var i = 0; i < items.length; i++) {
    if (items[i] < 0) continue;
    if (items[i] == 10) break;
    print(i);
  }
}

void literals() {
  final values = [1, 2, 3];
  for (var j = 0; j < values.length; j++) {
    print(values[j]);
  }
  List<String> names = ['Ada', 'Grace'];
  for (var n = 0; n < names.length; n += 1) {
    print(names[n]);
  }
}
Use a `for-in` loop; use `.indexed` when the index is needed.
1void canonical(List<int> items) {
2 for (var i = 0; i < items.length; i++) {
Use a `for-in` loop; use `.indexed` when the index is needed.
4 }
5 for (int index = 0; index < items.length; ++index) {
Use a `for-in` loop; use `.indexed` when the index is needed.
7 }
8 for (var i = 0; i < items.length; i += 1) {
Use a `for-in` loop; use `.indexed` when the index is needed.
10 }
11 for (var i = (0); (i) < (items.length); i++)
Use a `for-in` loop; use `.indexed` when the index is needed.
12 print(items[i]);
13 for (var i = 0; i < items.length; i++) {
Use a `for-in` loop; use `.indexed` when the index is needed.
21 final values = [1, 2, 3];
22 for (var j = 0; j < values.length; j++) {
Use a `for-in` loop; use `.indexed` when the index is needed.
25 List<String> names = ['Ada', 'Grace'];
26 for (var n = 0; n < names.length; n += 1) {

Valid

example.dartdart
void boundaries(List<int> items, List<int> other) {
  for (final item in items) {
    print(item);
  }
  for (var i = 1; i < items.length; i++) {
    print(items[i]);
  }
  for (var i = 0; items.length > i; i++) {
    print(items[i]);
  }
  for (var i = 0; i <= items.length; i++) {
    print(i);
  }
  for (var i = 0; i < items.length; i += 2) {
    print(items[i]);
  }
  for (var i = 0; i < items.length; i--) {
    print(items[i]);
    break;
  }
  for (var i = 0; i < items.length; i++) {
    i += 1;
    print(items[i]);
  }
  for (var i = 0; i < items.length; i++) {
    items.add(i);
  }
  for (var i = 0; i < items.length; i++) {
    items[i] = 0;
  }
  for (var i = 0; i < items.length; i++) {
    items = other;
  }
  for (var i = 0; i < items.length; i++) {
    print(items[i + 1]);
  }
  for (var i = 0; i < items.length; i++) {
    print(items);
  }
  for (var i = 0, j = 0; i < items.length; i++, j++) {
    print(items[i]);
  }
  var index = 0;
  for (index = 0; index < items.length; index++) {
    print(items[index]);
  }
  for (var i = 0; i < items.length; i++) {
    final callback = () => items[i];
    print(callback);
  }
  for (var i = 0; i < items.length; i++) {
    final alias = items;
    alias.clear();
  }
  for (var i = 0; i < items.length; i++) {
    final i = 1;
    print(items[i]);
  }
  for (var i = 0; i < items.length; i++) {
    (i, index) = (1, 2);
  }
}

void nonLists(String text, Map<int, int> entries, dynamic unknown) {
  for (var i = 0; i < text.length; i++) {
    print(text[i]);
  }
  for (var i = 0; i < entries.length; i++) {
    print(entries[i]);
  }
  for (var i = 0; i < unknown.length; i++) {
    print(unknown[i]);
  }
}

class Owner {
  List<int> items = [1, 2];
  void fields() {
    for (var i = 0; i < items.length; i++) {
      print(items[i]);
    }
    for (var i = 0; i < this.items.length; i++) {
      print(this.items[i]);
    }
  }
}

Future<void> suspension(List<int> items) async {
  for (var i = 0; i < items.length; i++) {
    await Future<void>.value();
    print(items[i]);
  }
}

Configure prefer-for-in

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "prefer-for-in": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/style/prefer-for-in: <reason>