avoid-slow-collection-methods

Path
lint/performance/avoid-slow-collection-methods
Default
Off, opt in
Origin
Falcon
Rule
143 of 512

Reports filtered iterable searches that have a direct search-method alternative.

On confirmed SDK Iterable APIs, where(test).first, .last, and .single can use firstWhere, lastWhere, and singleWhere without creating a filtering iterable. The lastWhere recommendation requires a pure predicate: a list may search backward and stop early, changing predicate evaluation order and count. No automatic fix is offered. Lazy expand calls are not reported: eagerly spreading them could change evaluation timing.

Only explicit, non-null-aware chains with one positional callback match. Source overrides, unrelated lookalike APIs, and unresolved receivers are excluded. Arrow closures testing their parameter with is T belong to prefer-iterable-where-type; length and membership checks belong to prefer-is-empty and prefer-contains, respectively. No arbitrary sync* function is classified as slow merely because it is a generator.

Invalid

example.dartdart
bool positive(int value) => value > 0;

void search(Iterable<int> values, List<int> list, Set<int> set) {
  values.where(positive).first;
  values.where(positive).last;
  values.where(positive).single;
  list.where((value) => value > 2).first;
  set.where((value) => value.isEven).last;
  (values.where((value) => value < 10)).single;
  <int>[1, 2, 3].where(positive).first;
  values.map((value) => value + 1).where(positive).first;
}

void typeFilters(Iterable<Object> values, Object other) {
  values.where((value) => value is! String).first;
  values.where((value) { return value is String; }).first;
  values.where((value) => other is String).first;
}
Use `firstWhere` instead of `where(...).first`.
3void search(Iterable<int> values, List<int> list, Set<int> set) {
4 values.where(positive).first;
With a pure predicate, use `lastWhere`; predicate evaluation order and count may change.
4 values.where(positive).first;
5 values.where(positive).last;
Use `singleWhere` instead of `where(...).single`.
5 values.where(positive).last;
6 values.where(positive).single;
Use `firstWhere` instead of `where(...).first`.
6 values.where(positive).single;
7 list.where((value) => value > 2).first;
With a pure predicate, use `lastWhere`; predicate evaluation order and count may change.
7 list.where((value) => value > 2).first;
8 set.where((value) => value.isEven).last;
Use `singleWhere` instead of `where(...).single`.
8 set.where((value) => value.isEven).last;
9 (values.where((value) => value < 10)).single;
Use `firstWhere` instead of `where(...).first`.
9 (values.where((value) => value < 10)).single;
10 <int>[1, 2, 3].where(positive).first;
Use `firstWhere` instead of `where(...).first`.
10 <int>[1, 2, 3].where(positive).first;
11 values.map((value) => value + 1).where(positive).first;
Use `firstWhere` instead of `where(...).first`.
14void typeFilters(Iterable<Object> values, Object other) {
15 values.where((value) => value is! String).first;
Use `firstWhere` instead of `where(...).first`.
15 values.where((value) => value is! String).first;
16 values.where((value) { return value is String; }).first;
Use `firstWhere` instead of `where(...).first`.
16 values.where((value) { return value is String; }).first;
17 values.where((value) => other is String).first;

Valid

example.dartdart
import 'dart:async';

bool positive(int value) => value > 0;

class Query {
  Query where(bool Function(int) predicate) => this;
  int get first => 0;
  int get last => 0;
  int get single => 0;
}

abstract class CustomIterable implements Iterable<int> {
  @override
  Iterable<int> where(bool Function(int) predicate) => <int>[1];
}

void search(Iterable<int> values, Iterable<Object> objects,
    Iterable<int>? nullable, dynamic unknown, Query query, CustomIterable custom) {
  values.firstWhere(positive);
  values.where(positive);
  values.first;
  values.where(positive).isEmpty;
  values.where(positive).length == 0;
  objects.where((value) => value is String).first;
  objects.where((value) => (value is int)).last;
  objects.where((value) => value is num).single;
  nullable?.where(positive).first;
  unknown.where(positive).first;
  query.where(positive).first;
  query.where(positive).last;
  query.where(positive).single;
  custom.where(positive).first;
}

void membership(List<int> values) {
  values.indexOf(1) >= 0;
}

void streamSearch(Stream<int> values) {
  values.where(positive).first;
}

Configure avoid-slow-collection-methods

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "performance": {
        "avoid-slow-collection-methods": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/performance/avoid-slow-collection-methods: <reason>