Alexander Arendar
Alexander Arendar

Reputation: 3425

Clarification on avoid_null_checks_in_equality_operators linter rule

There is a linter rule which verifies that one don't check for null equality in the overridden == operator. The rule is here.

I understand this rule but can't see how it is realized technically. It seems that Dart itself makes some implicit check on other != null and == returns false in this case. Is this correct?

In other languages, e.g. Java, one needs to explicitly add this check in the overridden equals.

Second question is why then it does not check automatically on the type of other as well. Why it is ok to spare me as a programmer from checking on null, but I still need to check if other is Person? Are there cases when one overrides == and checks there for some other type then the type of that class?

Upvotes: 0

Views: 119

Answers (3)

lrn
lrn

Reputation: 71693

The linter rule implementation is simple, it just checks whether you compare the argument of operator == to null. The reason you don't need to is that e1 == e2 in Dart is defined to first evaluate e1 and e2 to a value, then give a result early if one or both of the values is null, and only otherwise it calls the operator== method on the value of e1. So, when that method is called, you know for certain that the argument is not null.

The reason the == operator doesn't do more checks before calling the operator== method is that there are examples where that would be wrong. In particular, int and double can be equal to each other. Having instances of different classes potentially being equal to each other is more common that you'd think (proxies, mocks, wrappers, Cartesian point vs polar point, int vs double).

The other check you could potentially do early is to say that an object is equal to itself, so if (identical(this, other)) return true;, but there is one counter-example forced upon the language: NaN, aka. double.nan. That particular "value" is not equal to itself (which breaks the reflexivity requirement for ==, but is specified that way by the IEEE-754 standard which is what the CPUs implement natively). If not for NaN, the language would probably have checked for identity before calling operator== too.

Upvotes: 2

jamesdlin
jamesdlin

Reputation: 89995

It seems that Dart itself makes some implicit check on other != null and == returns false in this case. Is this correct?

Yes.

Second question is why then it does not check automatically on the type of other as well. Why it is ok to spare me as a programmer from checking on null, but I still need to check if other is Person? Are there cases when one overrides == and checks there for some other type then the type of that class?

It's less common, but there can be cases where you might want to allow a different type on the right-hand-side of the equality. For example, the left-hand-side and right-hand-side might be easily convertible to each other or to a common type. Imagine that you created, say, a Complex number class and that you wanted Complex(real: 4.0, imaginary: 0.0) == 4 to be true.

Upvotes: 1

scrimau
scrimau

Reputation: 1385

From the doc:

no class can be equivalent to [null]

Meaning, when other is Person is true, then other != null is also true. This is because:

The null object is the sole instance of the built-in class Null.

(https://dart.dev/guides/language/spec)

So every instance check against any type but Null will return false for null:

class A {}

void main() {
  final x = null;
  final a = A();
  print(x is Null); // true
  print(x is A);    // false
  print(a is Null); // false
  print(a is A);    // true
} 

Upvotes: 0

Related Questions