prefer-is-empty

Same as prefer_is_empty in Dart lints

Group
Style
Path
lint/style/prefer-is-empty
Default
On (recommended)
Origin
Dart lints
Rule
376 of 512
recommended

Flags .length comparisons equivalent to a .isEmpty check.

Collections and strings expose an isEmpty getter that states intent directly and, for lazy iterables, can be cheaper than computing the full length. Comparing length against a constant forces the reader to decode the boundary, so list.isEmpty should replace forms such as length == 0, length < 1, and length <= 0, together with their operand-swapped mirrors (0 == length, 1 > length, 0 >= length).

Only a plain .length property access matches against the relevant integer literal. A null-aware receiver?.length is deliberately left alone: that comparison also has to account for a null receiver, so isEmpty is not a drop-in replacement.

Semantic analysis requires declaration identities. Once available, an unknown receiver still triggers the lint. A TypeIndex can suppress it only when the receiver is proven to have no isEmpty member and not to be an Iterable, String, or Map; source-resolved members and subtypes take precedence. Without a type index, those negative proofs are unavailable, but source-derived receiver types are still inferred.

Invalid

example.dartdart
void bad() {
  if (list.length == 0) return;
  if (0 == items.length) return;
  if (str.length < 1) return;
  if (map.length <= 0) return;
  if (1 > set.length) return;
  if (0 >= names.length) return;
}

// A class implementing a core collection still inherits `isEmpty` (from
// Iterable), so the suggestion is valid and the diagnostic keeps firing.
class Bag implements Iterable<int> {
  int get length => 0;
}

// A class whose supertype chain leaves the project is `Unknown`, never
// `ProvenAbsent` — an unresolved ancestor could contribute `isEmpty` — so the
// diagnostic keeps firing (type knowledge suppresses only on positive proof).
class Offsite extends Frobnicator {
  int get length => 0;
}

void typedReceivers(Bag b, Offsite o) {
  if (b.length == 0) return;
  if (o.length == 0) return;
}

// A static method returns some other type (a Map here), not the enclosing class,
// so `Config.load()` is Unknown, never `Config`. Typing it as `Config` (a named
// constructor guess) would wrongly suppress; the diagnostic must keep firing.
class Config {
  static Map<String, String> load() => {};
}

void staticCallReceiver() {
  if (Config.load().length == 0) return;
}
Use `isEmpty` instead of comparing `length` to 0.
1void bad() {
2 if (list.length == 0) return;
Use `isEmpty` instead of comparing `length` to 0.
2 if (list.length == 0) return;
3 if (0 == items.length) return;
Use `isEmpty` instead of comparing `length` to 0.
3 if (0 == items.length) return;
4 if (str.length < 1) return;
Use `isEmpty` instead of comparing `length` to 0.
4 if (str.length < 1) return;
5 if (map.length <= 0) return;
Use `isEmpty` instead of comparing `length` to 0.
5 if (map.length <= 0) return;
6 if (1 > set.length) return;
Use `isEmpty` instead of comparing `length` to 0.
6 if (1 > set.length) return;
7 if (0 >= names.length) return;
Use `isEmpty` instead of comparing `length` to 0.
23void typedReceivers(Bag b, Offsite o) {
24 if (b.length == 0) return;
Use `isEmpty` instead of comparing `length` to 0.
24 if (b.length == 0) return;
25 if (o.length == 0) return;
Use `isEmpty` instead of comparing `length` to 0.
35void staticCallReceiver() {
36 if (Config.load().length == 0) return;

Valid

example.dartdart
void good() {
  if (list.isEmpty) return;
  if (items.length == 2) return;
  if (str.length > 0) return;
  if (map.length != 0) return;
  if (set.length >= 1) return;
  if (count == 0) return;
}

// A user class with only a `length` getter — no `isEmpty`, and not a core
// collection/string. Its receiver type is positively proven, so `length == 0`
// is SUPPRESSED: suggesting `isEmpty` would reference a member it does not have.
// (Requires the corpus harness to attach a TypeIndex for this rule; without one
// the receiver is Unknown and this line would fire.)
class Ruler {
  int get length => 3;
}

void suppressed(Ruler r) {
  if (r.length == 0) return;
}

// A named constructor `Box.zero()` still resolves to a `Box` instance (a real
// constructor is not a declared member), and `Box` has only `length` and is no
// collection — so this stays SUPPRESSED, unlike a static-method call.
class Box {
  Box.zero();
  int get length => 0;
}

void suppressedCtor() {
  if (Box.zero().length == 0) return;
}

Configure prefer-is-empty

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "prefer-is-empty": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/style/prefer-is-empty: <reason>
  • prefer-is-not-emptyprefer_is_not_emptyrecommended

    Flags .length comparisons equivalent to a .isNotEmpty check.

  • prefer-is-not-operatorprefer_is_not_operatorrecommended

    Flags a negated type test !(x is T) that should use the is! operator.

  • prefer-iterable-ofprefer-iterable-ofrecommended

    Flags .from collection constructors in favor of the .of constructor.

  • prefer-iterable-where-typeprefer_iterable_whereTyperecommended

    Flags .where((e) => e is T), which .whereType<T>() expresses directly.

  • prefer-lastprefer-last

    Flags manual last-element indexing in favor of the .last getter.

  • prefer-match-file-name

    Match a file's sole class or enum name to its snake-case basename.

  • prefer-mixinprefer_mixinrecommended

    Flags with clauses that mix in a plain class instead of a mixin.

  • prefer-multi-bloc-providerbloc

    Flatten directly nested package:flutter_bloc BlocProviders with MultiBlocProvider.