You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Summary: The TypedDataList class does not override the operator == method, forcing users to rely on a separate equals method for comparisons. This leads to potential inconsistencies and silent failures if users inadvertently use == instead of equals. The user suggests overriding == to perform list comparison for consistency.
Plain Dart Lists also do not override Object.==. It's a design choice to not have == on mutable objects, because being equal by content may be a fleeting property that can change at any time.
Also, it requires having a non-trivial hashCode that agrees with it.
It's unclear whether Uint8List.fromList([1, 2]) should equals Uint32List.fromList([1, 2]).
They are lists with the same length and equal elements, but they are also clearly different in very significant ways.
How about Float32List.fromList([1.0, 2.0]) which also contains elements that are equal with the other two?
If we have that kind of equality, then it's not going to be efficient. It won't be using memcmp on any typed-data lists that have different number types.
Being very efficient would be a reason to have special equality, but if it's only for two Uint8Lists, meaning that the equality will have to compare the types first to see if it can use the efficient branch, then there is little point. (And that would still not work for a Float32List or Float64List that contains NaN values, which should not be compared as bits).
I don't see us changing this design at the current time.
If we did it for typed-data lists, why not for normal lists (which is definitely going to be list length + element equality), but then type-data lists areLists, so they should have the same inefficient equality.
And doing something more efficient for typed-data lists could block adding equality to plain Lists. (If we wanted to.)
I'll recommend just using ListEquality from package:collection.
Thanks for the detailed response. I had noticed other issues being raised about the possibility of const typed data and wondered how equality would be handled in that scenario. That makes sense that it would need a special case from plain List - but since some of the typed data are immutable (Float64x2) it seemed like a good candidate. But I can see how special casing it would be inefficient. If extension types could override this behavior (and delegate to ListEquality), that would be preferable, but not being able to override Object members prevents this. Not being able to override Object (for extensions), combined with trivial equality on typed data makes it difficult to implement a 2d vector backed by typed data. Both Offset (Flutter) and Point (dart:math) implement comparison.
If two constant Uint8List values with the same value would likely be canonicalized to the same object instance, at which point == would work, since the Object.== implementation is just => identical(this, other);.
I would have no problem with Float64x2 having ==, it's not a list and it's not mutable, it really is a data object.
It probably still wouldn't be able to be done as a memcmp, since we'd want to consider NaN values not equal to themselves.
Good point about const, the equality would work there. IMO the way equality works is best now for Uint8List as length + element equality could be a performance cliff if the comparison is made implicitly as part of a larger data object. Not being able to override this behavior though is the limiting factor as an application can't decide if that comparison is worthwhile. Float64x2== comparison would be great, and it would solve 2d vector, but a Rect would need to be backed by a Float64List and wouldn't be able to benefit here - there is Float32x4 but not Float64x4.
Activity
dart-github-bot commentedon Aug 8, 2024
Summary: The
TypedDataListclass does not override theoperator ==method, forcing users to rely on a separateequalsmethod for comparisons. This leads to potential inconsistencies and silent failures if users inadvertently use==instead ofequals. The user suggests overriding==to perform list comparison for consistency.lrhn commentedon Aug 12, 2024
Plain Dart
Lists also do not overrideObject.==. It's a design choice to not have==on mutable objects, because being equal by content may be a fleeting property that can change at any time.Also, it requires having a non-trivial
hashCodethat agrees with it.It's unclear whether
Uint8List.fromList([1, 2])should equalsUint32List.fromList([1, 2]).They are lists with the same length and equal elements, but they are also clearly different in very significant ways.
How about
Float32List.fromList([1.0, 2.0])which also contains elements that are equal with the other two?If we have that kind of equality, then it's not going to be efficient. It won't be using
memcmpon any typed-data lists that have different number types.Being very efficient would be a reason to have special equality, but if it's only for two
Uint8Lists, meaning that the equality will have to compare the types first to see if it can use the efficient branch, then there is little point. (And that would still not work for aFloat32ListorFloat64Listthat contains NaN values, which should not be compared as bits).I don't see us changing this design at the current time.
If we did it for typed-data lists, why not for normal lists (which is definitely going to be list length + element equality), but then type-data lists are
Lists, so they should have the same inefficient equality.And doing something more efficient for typed-data lists could block adding equality to plain
Lists. (If we wanted to.)I'll recommend just using
ListEqualityfrompackage:collection.curt-weber commentedon Aug 12, 2024
Thanks for the detailed response. I had noticed other issues being raised about the possibility of
consttyped data and wondered how equality would be handled in that scenario. That makes sense that it would need a special case from plainList- but since some of the typed data are immutable (Float64x2) it seemed like a good candidate. But I can see how special casing it would be inefficient. Ifextension typescould override this behavior (and delegate toListEquality), that would be preferable, but not being able to overrideObjectmembers prevents this. Not being able to overrideObject(for extensions), combined with trivialequalityon typed data makes it difficult to implement a 2d vector backed by typed data. BothOffset(Flutter) andPoint(dart:math) implement comparison.lrhn commentedon Aug 13, 2024
If two constant
Uint8Listvalues with the same value would likely be canonicalized to the same object instance, at which point==would work, since theObject.==implementation is just=> identical(this, other);.I would have no problem with
Float64x2having==, it's not a list and it's not mutable, it really is a data object.It probably still wouldn't be able to be done as a
memcmp, since we'd want to consider NaN values not equal to themselves.curt-weber commentedon Aug 13, 2024
Good point about
const, the equality would work there. IMO the way equality works is best now forUint8Listaslength + element equalitycould be a performance cliff if the comparison is made implicitly as part of a larger data object. Not being able to override this behavior though is the limiting factor as an application can't decide if that comparison is worthwhile.Float64x2==comparison would be great, and it would solve 2d vector, but aRectwould need to be backed by aFloat64Listand wouldn't be able to benefit here - there isFloat32x4but notFloat64x4.