Comments (1)
The provided example does showcase some of the issues related to immutability, but it falls short in demonstrating the pitfalls of mutable objects when used in hashed collections like HashSet.
The reason your test cases might be passing (i.e., expect(equatableImmune1, equatableImmune2);) is that you are comparing objects that were effectively created to be the same, and the Equatable package is performing deep equality checks. The test doesn't simulate a scenario where you would change an object after it has been inserted into a hashed collection, which is where the issues with mutability usually arise.
Here's a modified example to showcase the point. This version shows how mutable objects can cause issues when their state changes after they've been added to a HashSet:
void main() {
final setWithImmutable = HashSet<_EquatableTest>();
final setWithMutable = HashSet<_EquatableTestNonImmutable>();
final immutableObj = _EquatableTest(values: HashSet.from([1, 2, 3]));
final mutableObj = _EquatableTestNonImmutable(values: HashSet.from([1, 2, 3]));
// Add objects to sets
setWithImmutable.add(immutableObj);
setWithMutable.add(mutableObj);
print('Before mutation:');
print('Immutable set contains object: ${setWithImmutable.contains(immutableObj)}'); // Should print true
print('Mutable set contains object: ${setWithMutable.contains(mutableObj)}'); // Should print true
// Mutate the internal state of the objects
final mutatedImmutableObj = immutableObj.copyWith(values: HashSet.from([4, 5, 6]));
mutableObj.values = HashSet.from([4, 5, 6]);
print('After mutation:');
print('Immutable set contains object: ${setWithImmutable.contains(immutableObj)}'); // Should still print true
print('Mutable set contains object: ${setWithMutable.contains(mutableObj)}'); // Should print false
}
class _EquatableTest extends Equatable {
final HashSet values;
const _EquatableTest({required this.values});
@override
List<Object?> get props => [values];
_EquatableTest copyWith({
HashSet? values,
}) {
return _EquatableTest(
values: values ?? this.values,
);
}
}
class _EquatableTestNonImmutable extends Equatable {
HashSet values;
_EquatableTestNonImmutable({required this.values});
@override
List<Object?> get props => [values];
}
In this example, you'll see that after mutating the internal HashSet of the mutable object, the main HashSet (setWithMutable) can no longer recognize it. This is because its hash code changes when its internal state changes. On the other hand, the immutable object remains recognizable by the main HashSet (setWithImmutable) even after "mutation", as it actually results in a new object while keeping the original object unchanged.
Here is another example:
void main() {
// Mutable object test
final mutableSet = <_Mutable>{};
final mutable = _Mutable(value: 1);
// Add mutable object to set
mutableSet.add(mutable);
print('Mutable contains before mutation: ${mutableSet.contains(mutable)}'); // Output: true
// Mutate object
mutable.value = 2;
// Check if set still contains the object
print('Mutable contains after mutation: ${mutableSet.contains(mutable)}'); // Output: false
// Immutable object test
final immutableSet = <_Immutable>{};
var immutable = _Immutable(value: 1);
// Add immutable object to set
immutableSet.add(immutable);
print('Immutable contains before mutation: ${immutableSet.contains(immutable)}'); // Output: true
// "Mutate" object by creating a new one
immutable = immutable.copyWith(value: 2);
// Check if set still contains the object
print('Immutable contains after mutation: ${immutableSet.contains(immutable)}'); // Output: false
// Check if set still contains the original object
print('Immutable contains original after mutation: ${immutableSet.contains(_Immutable(value: 1))}'); // Output: true
}
class _Mutable {
int value;
_Mutable({required this.value});
@override
int get hashCode => value;
@override
bool operator ==(Object other) =>
identical(this, other) || (other is _Mutable && other.value == value);
}
class _Immutable {
final int value;
_Immutable({required this.value});
_Immutable copyWith({int? value}) {
return _Immutable(value: value ?? this.value);
}
@override
int get hashCode => value;
@override
bool operator ==(Object other) =>
identical(this, other) || (other is _Immutable && other.value == value);
}
from equatable.
Related Issues (20)
- Same hashcode for different new lists HOT 1
- Equality and Hashcode differ for Sets with different order
- Equatable doesn't checks for Equality for variables in parent class HOT 3
- feat request: add `stringifyProps` HOT 4
- Enum implementing Equatable related classes HOT 5
- Same object, same runtimeType but runtimeType== other.runtimeType is false HOT 3
- Storing the hashCode HOT 3
- Doesn't work with List<File> as property HOT 1
- `runtimeType` prevents from using generic type HOT 5
- Provide lint for forgotten fields in props HOT 3
- List of object dosen't work correctly HOT 12
- `Equatable` is redundant with `EquatableMixin` HOT 2
- Upgrade sdk to include Dart 3 HOT 3
- A Map considered equal even if its not HOT 3
- Why do we need to compare runtimeType? HOT 5
- Support for mutable class objects HOT 3
- `Foo(1) == Foo(1.0)` is false HOT 2
- Publish a new version HOT 2
- Is that logical? Object equals but element not equals. HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from equatable.