From 0f5d54b7355a44875dbd0bab3853cf11233bb90b Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Tue, 3 Jan 2023 17:08:10 +0100 Subject: [PATCH] `BuiltList` won't compute hash as part of `==`. The implementation of `BuiltList.operator==` used `this.hashCode != other.hashCode` as a short-cut in operator `==`. However, computing `hashCode` can be as expensive as doing equality, since it has to visit all the same objects (otherwise the hash code won't be consistent with equality) and do a computation on each. This change makes the `hashCode` only be used if it's already computed by both `this` and `other`, in which case it should be free. It's a change in performance-behavior. A single `==` won't do double work, but repeated `==`s on the same objects might have been more efficient if the hash code was computed eagerly. For elements in a set or map, the hash code will be computed anyway, so it should not affect those. Having a list of `BuiltList`s and doing repeated `indexOf` with the same values on the list might suffer. I believe the trade-off is worth it, because most lists are not compared for equality, and those that are, are either one-off comparisons, or used as map keys or set elements. --- lib/src/list/built_list.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/src/list/built_list.dart b/lib/src/list/built_list.dart index 6dd8638..3cbf597 100644 --- a/lib/src/list/built_list.dart +++ b/lib/src/list/built_list.dart @@ -65,10 +65,7 @@ abstract class BuiltList implements Iterable, BuiltIterable { /// A `BuiltList` is only equal to another `BuiltList` with equal elements in /// the same order. Then, the `hashCode` is guaranteed to be the same. @override - int get hashCode { - _hashCode ??= hashObjects(_list); - return _hashCode!; - } + int get hashCode => _hashCode ??= hashObjects(_list); /// Deep equality. /// @@ -79,7 +76,11 @@ abstract class BuiltList implements Iterable, BuiltIterable { if (identical(other, this)) return true; if (other is! BuiltList) return false; if (other.length != length) return false; - if (other.hashCode != hashCode) return false; + if (_hashCode != null && + other._hashCode != null && + _hashCode != other._hashCode) { + return false; + } for (var i = 0; i != length; ++i) { if (other[i] != this[i]) return false; }