Emptiness tested through length instead of isEmpty

ID

dart.performance.container_size_empty

Severity

info

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Idiom

Language

Dart

Description

Reports an emptiness test written as a comparison on length - length == 0, 0 == length, length ⇐ 0 or length < 1 - on a collection, String or any other object exposing length.

Rationale

length is not a stored field on every Iterable. For a lazy sequence - the result of map, where, expand, takeWhile or a synchronous generator - reading it walks and materialises the whole sequence just to compare the count against zero, while isEmpty stops after the first element. On an infinite or very long generator that difference is the whole cost of the expression. Comparing against zero also states the test indirectly: a reader has to work out which side of the comparison means empty, and the four spellings above all mean the same thing while looking different in review.

The following code illustrates the pattern detected by this rule:

class Cart {
  final List<String> lines;
  final Map<String, int> quantities;

  Cart(this.lines, this.quantities);

  String summary() {
    // FLAGGED: Emptiness tested through length instead of isEmpty
    if (lines.length == 0) {
      return 'empty cart';
    }
    // FLAGGED: Emptiness tested through length instead of isEmpty
    if (0 == quantities.length) {
      return 'nothing to price';
    }
    return 'ok';
  }
}

Remediation

Replace the comparison with isEmpty, which every Iterable, Map and String provides and which short-circuits on the first element. Where the count is genuinely needed for something else, read length once into a local and compare that.

Configuration

This detector does not need any configuration.

© 2026 Xygeni. All rights reserved