Update: For the new version of Equitable package >= v 0.6.0 read my article on Medium, for older version or deep understanding read this answer.
When your father gives you and your brother 2 gifts, both gifts are laptops but they are not the same type of laptops; you want to know are both gifts equal or not! So you will compare all aspects that important to you RAM, SSD, CPU.
on a paper: myLaptop: 16G/256G/i5 | myBrotherLaptop: 8G/512G/i5
Assuming your brain is using Dart language, and you thought of each gift as an object of this class:
class LaptopGiftClass {
int ram;
int ssd;
String cpu;
// Default constructor
LaptopGiftClass(this.ram, this.ssd, this.cpu);
}
then to compare Equailty of both gifts that created using the class above, Dart and other Object oriented languages e.g Java, C# are expecting you to create(override) these functions, in order to make these languages understand the objects and able to compare any two objects of same class:
@override
bool operator ==(Object myBrotherLaptop) =>
identical(myLaptop, myBrotherLaptop) ||
myBrotherLaptop is LaptopGiftClass &&
runtimeType == myBrotherLaptop.runtimeType &&
name == myBrotherLaptop.name;
@override
int get hashCode => name.hashCode;
if these lines scares you off, no one blame you, that's why nice people have created equatable package for us!
Equatable package is telling you "leave this scary job for me" But how to delegate the scary code to equatable package??!
By doing two things:
- Make your class extends equatable:
dart class LaptopGiftClass extends Equatable {...}
- Pass all properties that you need to compare with inside an array to the Equatable(the super/parent class) from moment one, so inside the constructor:
LaptopGiftClass(this.ram, this.ssd, this.cpu) : super([ram, ssd, cpu]);
your final class is:
class LaptopGiftClass extends Equatable {
int ram;
int ssd;
String cpu;
// Default constructor
LaptopGiftClass(this.ram, this.ssd, this.cpu) : super([ram, ssd, cpu]);
}
AND YOU ARE DONE! you can now check equality of the two gifts, just create the objects then compare:
LaptopGiftClass myLaptop = LaptopGiftClass(16,256,'i5');
LaptopGiftClass myBrotherLaptop = LaptopGiftClass(8, 512,'i5');
AND JUST BEFORE START COMPARING, your brother saw you, and because he is a gamer, he wants you to add more properties in this equality check: GPU and Screen_Resolution! your mother heard that and asked you to add price too!
Now you have a list of new props to compare: [GPU, Screen_Resolution, Price].
So because you follow clean code principle, you expected that, and you made the constructor able to get more properties to compare with:
// This only mean combine both lists
[ram, ssd, cpu]..addAll(myBrotherAndMotherProps)
so your final class is:
class LaptopGiftClass extends Equatable {
int ram;
int ssd;
String cpu;
// Default constructor
LaptopGiftClass(
this.ram,
this.ssd,
this.cpu,
// List of list => because we think "clean code"
// and maybe in the future we will send other data; NOT
// only an array(list)..
// so we here sent the extra props we need to
// compare 'myBrotherAndMotherProps', and
// as sometime brother and mother will not ask you
// to add props to compare, you give it a default value
// as empty "const []", why const here??! just for better
// performance as we are so soooo Professional!!
[ List myBrotherAndMotherProps = const [] ],
) : super([ram, ssd, cpu]..addAll(myBrotherAndMotherProps));
// WHY TO PASS FROM INSIDE THE CONSTRUCTOR?
// because Equatable needs them (required)
// and not at anytime but immediately inside the
// constructor of itself, so we made this
// chaining(constructor pass to another constructor)..
}
So it's obvious that the essintial properties are [RAM, SSD, CPU], but anything extra will be take into consideration too as we made the implementation clean, flexible, and scalable.
before adding this flexible code List<Object> get props => [RAM, SSD, CPU]..addAll(myBrotherAndMotherProps);
these used to be EQUAL!!:
// Note first 3 are equal [ram, ssd, cpu]:
LaptopGiftClass myLaptop = LaptopGiftClass(16,256,'i5', ['Nvidia', 1080, '1200$']);
LaptopGiftClass myBrotherLaptop = LaptopGiftClass(16, 256,'i5', ['Intel HD', 720, '900$']);
myLaptop == myBrotherLaptop; // True without ..addAll(myBrotherAndMotherProps);
myLaptop == myBrotherLaptop; // False with ..addAll(myBrotherAndMotherProps);
Same happening with TimerState:
@immutable
abstract class TimerState extends Equatable {
final int duration;
TimerState(this.duration, [List props = const []])
: super([duration]..addAll(props));
}
TimerState
is implemented just like LaptopGiftClass
above(last implementation).
you can send props
to it using the constructor:
TimerState(this.duration, [List props = const []])
: super([duration]..addAll(props));
so TimerState
will pass props's list to its parent(super/ the Equatable/ what extended..) in this line like this:
: super([duration]..addAll(props));
and in this timer example; duration
is the basic prop, just like [RAM, SSD, CPU]
to LaptopGiftClass.
and the hierarchy will be like this:
// Inside class Paused extends TimerState {...}
Paused(int duration) : super(duration); // super is TimerState
// then Inside abstract class TimerState extends Equatable {..}
TimerState(this.duration, [List props = const []])
: super([duration]..addAll(props)); // super is Equatable
// Then Equatable will get props and deal with it for you...
dart [List props = const []]
– Candart super([duration]..addAll(props));
mean – Canprop
getter method. – Duckboard