Equality in Flutter and Dart with Equatable
In this article, we will review how equality works in Dart and Flutter and how the Equatable package can help us to avoid writing a lot of boilerplate code.
We already know that If we want to compare two variables, we can use the ==
operator. For example, if we want to compare two strings, the code is:
final car1 = "Toyota";
final car2 = "Toyota";
print(car1 == car2); // Result: true
And if we want to compare two numbers, the code is:
final phone1 = 52123456;
final phone2 = 52123456;
print(phone1 == phone2); // Result: true
Let's run the previous code in DartPad:
Compare two different objects of the same class
In the previous examples, we learned that comparing two variables is easy using ==
, but when we want to compare two objects of the same class is not that easy.
If we have the following class:
class Car {
final String brand;
Car(this.brand);
}
And we create two objects with the same values:
final car1 = Car('Toyota');
final car2 = Car('Toyota');
print(car1 == car2); // false
We may think that car1
and car2
are equal, but they are not. Comparing car1
and car2
will be false
.
Let's run the previous code in DartPad:
Why is false
if all the values are the same? The answer is easy, in Dart, the operator ==
verifies the memory address and not the properties of the objects. Because car1
and car2
are in different memory addresses, the result is false
Using the const
constructor
Using the const
constructor tells Dart to create only one class instance for a given set of values at compile time. Let's run the previous code, but this time using const
constructors:
Using the const
constructors solves the equality problem but only works for objects we know at compile time. There is no way to use a const
constructor for objects created at runtime. This is where Equatable can help us.
Equatable package
Without the help of Equatable, if we want to compare the property values of two objects to check if they are the same, we have to override ==
and hashCode
. The Car
class code will be:
class Car {
final String brand;
const Car(this.brand);
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Car &&
runtimeType == other.runtimeType &&
brand == other.brand;
@override
int get hashCode => brand.hashCode;
}
Equatable makes it easier to compare objects of the same class without overriding ==
and hashCode
.
Internally Equatable overrides ==
and hashCode
so we do not waste time writing boilerplate code.
Using Equatable the previous code will be:
import 'package:equatable/equatable.dart';
class Car extends Equatable {
const Car(this.brand);
final String brand;
@override
List<Object> get props => [brand];
}
If we add more properties like name
, the code will be:
class Car extends Equatable {
const Car(this.brand, this.name);
final String brand;
final String name;
@override
List<Object> get props => [brand, name];
}
Let's run the previous code in DartPad:
Now, when we compare two objects with the same values, the result is true
. Try changing the values of car2
. What is the result?
Conclusion
Equatable is a handy package to compare objects of the same class. Without it, we will have to write a lot of boilerplate code.