“This is the 28th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

preface

In general, we do not implement a custom equality judgment for a class. Any object built with a different value or hash code will return false with the == judgment. In some cases, if we want to use == directly to determine whether our custom classes are equal, we need to override both the == operator and the hashCode method. This article summarizes what coding needs to do when using a custom object equality implementation.

Object equality judgment

Let’s start with a classic interview question in the Java language, which is the following code console output.

Integer a=127;
Integer b=127;
System.out.println(a==b);

Integer c=128;
Integer d=128;
System.out.println(c==d);
Copy the code

The result is that the first print is true and the second print is false. This is because Java uses caching for integer objects in the -128 to 127 range, and anything outside that range is newly built. So what does that look like in Dart?


  int a = 127;
  int b = 127;
  print(a == b);

  int c = 128;
  int d = 128;
  print(c == d);
Copy the code

The result returns true because Dart supports operator overloading, and the equality of two objects is actually determined using the == operator and hash code. Both int and double inherit from the numeric class num. For this type, the hash code is the value itself, and the == operator is actually evaluated using the compareTo method, so as long as the values of two numeric classes are equal (except for special values such as double-.nan, double-.infinity), Then it is equal when operating with the == comparator.

The same is true for string types, where string sequences are consistent, hash codes are consistent. However, for Unicode, hash codes are not equal if different encodings are used. Therefore, in Dart, comparing string equality does not require the Java-like equals method. Instead, the == operator is used.

This actually gives us another flexibility, such as overwriting the == operator and the hashCode method when we want two objects of the same type to be equal. For example, whether the Widget is refreshed or not, as we discussed in Redux, because every time Redux returns a new State object, you can do this if you want to reduce the refresh without changing the actual data. For details, see Redux’s use of Distinct attributes for performance optimization.

With this in mind, let’s take a look at the considerations when determining the equality of custom objects.

If you override the == operator, be sure to override the hashCode method as well

The default hashCode method produces a unique hash value — which means that normally two objects will only have equal hashes if they are uniform objects. When we override the == operator, that means we have some other definition of equality for objects of this class. The principle that objects are equal must satisfy that both have the same hash value. So if you don’t override the hashCode method, that means it will fail in some cases, such as maps and other hash-based collections, where even if the elements in the two collections meet the equality criteria, the two collections cannot meet the equality criteria because the hash values of the equal elements are different.

The == operator should satisfy mathematical equality rules

Mathematically, equality needs to satisfy three rules:

  • Reflexivity: i.ea == aShould always returntrue.
  • Symmetry: ifa == bSo b is equal to lambda is equal to lambda a is equal to lambdatrue.
  • Transitivity: ifa == b δΈ” b == c, thena == cAlso should betrue.

This means that our hashCode method or the == operator method cannot have equality judgments for certain attributes of an object that are filtered based on conditions. For example, if the object property is null, one of the three rules given to you may not be valid.

For mutable classes, you should avoid custom equality judgments

What are mutable classes? A class whose properties of an object may change during runtime. Because, considering the mathematical equality rules above, custom equality should take all attributes of the object into account when generating hashes. If these properties change during runtime, it means that the object’s hash value will change. This violates the principle of reflexivity (if the same object has different hashes, it is like if your girlfriend changes her hair and you can’t tell she is going to be hit), and in general, this change is unpredictable for hash-based sets, leading to errors in the equality judgment of sets.

Do not apply the arguments of the == operator to nullable objects

In Dart, NULL is only equal to itself, so the == operator should be called for equality only if the object being compared is not null.

// Correct example
class Person {
  final String name;
  / /...

  bool operator ==(Object other) => other is Person && name == other.name;
}

// Error example
class Person {
  final String name;
  / /...bool operator ==(Object? other) => other ! =null && other is Person && name == other.name;
}
Copy the code

Note: Objects were allowed to be NULL until Dart released its NULL Safety version. Even so, Dart does not use null to call the custom == method for equality. Therefore, in the non-NULL safety version (< 2.12), we do not need to handle NULL within the == method.

conclusion

This article describes the mechanism for object equality in Dart and the considerations for defining class object equality. For the most part, we won’t need to override object equality judgments ourselves, but when we do, follow these tips to avoid confusing problems.

I am dao Code Farmer with the same name as my wechat official account. This is a column about the introduction and practice of Flutter, providing systematic learning articles about Flutter. See the corresponding source code here: The source code of Flutter Introduction and Practical column. If you have any questions, please add me to the wechat account: island-coder.

πŸ‘πŸ» : feel the harvest please point a praise to encourage!

🌟 : Collect articles, easy to look back!

πŸ’¬ : Comment exchange, mutual progress!