avoid_collection_equality_checks
v0.3.0 Warning Collection & Type
Flags == or != where either side is a List, Set, Map or Iterable. Collections have no deep equality in Dart: two distinct instances are never equal, however identical their contents.
The comparison compiles and always answers false, so the branch it guards never runs:
bool hasSelectionChanged(List<String> previous, List<String> current) { return previous != current;}Here hasSelectionChanged returns true for every call — including when nothing changed — because previous and current are separate objects.
Compare contents with DeepCollectionEquality from package:collection:
import 'package:collection/collection.dart';
bool hasSelectionChanged(List<String> previous, List<String> current) { return !const DeepCollectionEquality().equals(previous, current);}For a flat list, ListEquality is cheaper and states the depth you expect:
import 'package:collection/collection.dart';
bool hasSelectionChanged(List<String> previous, List<String> current) { return !const ListEquality<String>().equals(previous, current);}Comparing a field inside a model
Section titled “Comparing a field inside a model”The same trap sits in a hand-written ==, where it silently makes every instance unequal:
// Don'tclass Cart { const Cart(this.items);
final List<String> items;
@override bool operator ==(Object other) => other is Cart && items == other.items;}// Doimport 'package:collection/collection.dart';
class Cart { const Cart(this.items);
final List<String> items;
@override bool operator ==(Object other) => other is Cart && const ListEquality<String>().equals(items, other.items);
@override int get hashCode => const ListEquality<String>().hash(items);}Known limitations
Section titled “Known limitations”Three shapes are deliberately accepted:
- A null check.
items == nullanditems != nullare the normal way to test presence and are never reported. - Two compile-time constants.
const [1, 2] == const [1, 2]istrue, because constant collections are canonicalized to one instance. Both sides must beconstfor the exemption to apply. - Neither side a collection. At least one operand must be a
List,Set,MaporIterable, so ordinary value comparisons are untouched.
See also: collection package
Configuration
Section titled “Configuration”This rule is in the core preset, so it is on with preset: core,
preset: recommended or preset: opinionated.
To turn it off:
rules: avoid_collection_equality_checks: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”prefer_overriding_parent_equality— Override == and hashCode when the parent class overrides them.list_all_equatable_fields— Ensure all fields are listed in Equatable props.prefer_equatable_mixin— Prefer using EquatableMixin instead of extending Equatable.avoid_collection_methods_with_unrelated_types— Avoid calling collection methods with arguments whose types are unrelated to the collection’s type parameter.