When you try to compare two pass-by-reference Objects like class, List, Map, Set or etc...
you will need to set variables as const variables to be able to compare them because the compiler compares them by address or hashCode like the below code.
class Foo {
final int a;
final int b;
final SomeClass c;
const Foo({required this.a, required this.b, required this.c});
}
class SomeClass {
final List values;
const SomeClass(this.values);
}
void main() {
const foo1 = Foo(a: 1, b: 1, c: SomeClass([]));
const foo2 = Foo(a: 1, b: 1, c: SomeClass([]));
final foo3 = Foo(a: 1, b: 1, c: SomeClass([]));
final foo4 = Foo(a: 1, b: 1, c: SomeClass([]));
print(foo1 == foo2); // true
print(foo3 == foo4); //false
print(foo1.hashCode == foo2.hashCode); // true
print(foo3.hashCode == foo4.hashCode); // false
}
But we have a big problem we can assign a constant to variables defined at compile time and we can't do this at runtime, see below solutions :)
solution 1:
will need to override hashCode and == methods like the below code.
void main() {
const foo1 = Foo(a: 1, b: 1, c: SomeClass([]));
const foo2 = Foo(a: 1, b: 1, c: SomeClass([]));
final foo3 = Foo(a: 1, b: 1, c: SomeClass([]));
final foo4 = Foo(a: 1, b: 1, c: SomeClass([]));
print(foo1 == foo2); // true
print(foo3 == foo4); //true
print(foo1.hashCode == foo2.hashCode); // true
print(foo3.hashCode == foo4.hashCode); // true
}
class Foo {
final int a;
final int b;
final SomeClass c;
const Foo({required this.a, required this.b, required this.c});
@override
int get hashCode => Object.hash(a.hashCode, b.hashCode, c.hashCode);
@override
bool operator ==(Object other) {
return identical(this, other) ||
other is Foo &&
runtimeType == other.runtimeType &&
hashCode == other.hashCode;
}
}
class SomeClass {
final List values;
const SomeClass(this.values);
@override
int get hashCode => Object.hashAll(values);
@override
bool operator ==(Object other) {
return identical(this, other) ||
other is Foo &&
runtimeType == other.runtimeType &&
hashCode == other.hashCode;
}
}
solution 2 (the best solution):
use Equtable package
void main() {
const foo1 = Foo(a: 1, b: 1, c: SomeClass([]));
const foo2 = Foo(a: 1, b: 1, c: SomeClass([]));
final foo3 = Foo(a: 1, b: 1, c: SomeClass([]));
final foo4 = Foo(a: 1, b: 1, c: SomeClass([]));
print(foo1 == foo2); // true
print(foo3 == foo4); //true
print(foo1.hashCode == foo2.hashCode); // true
print(foo3.hashCode == foo4.hashCode); // true
}
class Foo extends Equatable {
final int a;
final int b;
final SomeClass c;
const Foo({required this.a, required this.b, required this.c});
@override
List<Object?> get props => [a, b, c];
}
class SomeClass extends Equatable {
final List values;
const SomeClass(this.values);
@override
List<Object?> get props => [values];
}
the sources:
https://www.youtube.com/watch?v=DCKaFaU4jdk
https://api.flutter.dev/flutter/dart-core/Object/hashCode.html