Operator Overloading, Equality and Callable Objects
22.1 Operator Overloading
Overloadable: < > <= >= - + / ~/ * % | ^ & << >> >>> [] []= ~ ==. There are no custom operators.
class Vector {
final double x, y;
const Vector(this.x, this.y);
Vector operator +(Vector other) => Vector(x + other.x, y + other.y);
Vector operator -(Vector other) => Vector(x - other.x, y - other.y);
Vector operator *(double k) => Vector(x * k, y * k);
Vector operator -() => Vector(-x, -y);
double operator [](int i) => i == 0 ? x : y;
bool operator <(Vector o) => length < o.length;
double get length => (x * x + y * y); // squared length for brevity
@override
bool operator ==(Object other) => other is Vector && other.x == x && other.y == y;
@override
int get hashCode => Object.hash(x, y);
@override
String toString() => 'Vector($x, $y)';
}
void main() {
final v = const Vector(1, 2) + const Vector(3, 4) * 2;
print((v, -v, v[0], v == const Vector(7, 10)));
}22.2 Equality and hashCode
Rule: if you override ==, override hashCode (equal objects must have equal hash codes). Use Object.hash, Object.hashAll, and Object.hashAllUnordered.
Avoid the boilerplate with the equatable package, the freezed code generator, or records.
class Person {
final String name;
final int age;
const Person(this.name, this.age);
@override
bool operator ==(Object other) =>
identical(this, other) || other is Person && other.name == name && other.age == age;
@override
int get hashCode => Object.hash(name, age);
}22.3 Callable Objects and Comparable
class Multiplier {
final int factor;
Multiplier(this.factor);
int call(int value) => value * factor; // makes instances callable
}
final triple = Multiplier(3);
print(triple(5)); // 15
class Version implements Comparable<Version> {
final int major, minor;
Version(this.major, this.minor);
@override
int compareTo(Version other) =>
major != other.major ? major.compareTo(other.major) : minor.compareTo(other.minor);
}
final sorted = [Version(1, 10), Version(1, 2)]..sort();22.4 noSuchMethod
class Mock {
@override
dynamic noSuchMethod(Invocation invocation) {
print('Called ${invocation.memberName} with ${invocation.positionalArguments}');
return null;
}
}
(Mock() as dynamic).anything(1, 2); // only for dynamic calls or classes that implement interfaces without bodies