Last active
February 12, 2021 20:09
-
-
Save psygo/6ee55f7c744646b39a306c4645cd43ed to your computer and use it in GitHub Desktop.
FIC: Fast Immutable Collections Motivation Demonstration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import "package:collection/collection.dart"; | |
import "package:fast_immutable_collections/fast_immutable_collections.dart"; | |
import "package:meta/meta.dart"; | |
//------------------------------------------------------------------------------ | |
void main() { | |
//---------------------------------------------------------------------------- | |
print("With Regular Collections\n\n"); | |
const bob = Person("Bob"); | |
var people1 = People([bob]); | |
print(people1); | |
const jake = Person("Jake"); | |
var people2 = people1.add(jake); | |
print(people1); | |
print(people2); | |
print(people1 == people2); // false | |
print(people2 == People([bob, jake])); // true | |
print(people1.hashCode == people2.hashCode); // false | |
print(people2.hashCode == People([bob, jake]).hashCode); // true | |
//---------------------------------------------------------------------------- | |
print("\n\n"); | |
//---------------------------------------------------------------------------- | |
print("With FIC\n\n"); | |
var peopleWithFic1 = PeopleWithFic([bob].lock); | |
var peopleWithFic2 = peopleWithFic1.add(jake); | |
print(peopleWithFic1); | |
print(peopleWithFic2); | |
print(peopleWithFic1 == peopleWithFic2); // false | |
print(peopleWithFic2 == PeopleWithFic([bob, jake].lock)); // true | |
print(peopleWithFic1.hashCode == peopleWithFic2.hashCode); // false | |
print(peopleWithFic2.hashCode == PeopleWithFic([bob, jake].lock).hashCode); // true | |
//---------------------------------------------------------------------------- | |
} | |
//------------------------------------------------------------------------------ | |
@immutable | |
class PeopleWithFic { | |
final IList<Person> people; | |
PeopleWithFic(this.people); | |
PeopleWithFic add(Person person) => PeopleWithFic(people.add(person)); | |
@override | |
bool operator ==(Object other) => identical(this, other) || | |
other is PeopleWithFic && | |
runtimeType == other.runtimeType && | |
people == other.people; | |
@override | |
int get hashCode => people.hashCode; | |
@override | |
String toString() => people.toString(); | |
} | |
//------------------------------------------------------------------------------ | |
@immutable | |
class People { | |
final List<Person> _people; | |
People(List<Person> people): _people = List.of(people); | |
People._(this._people); | |
// An example "mutable" operaton. Now imagine dozens of these operations, | |
// each needing extra care from you in order to not cause any side effects. | |
People add(Person person) { | |
var newPeopleList = List.of(_people)..add(person); | |
return People._(newPeopleList); | |
} | |
// If you want to create value equality for this class, you will need to | |
// override reference equality. The simplest way is to do this is to use the | |
// collection package. | |
@override | |
bool operator ==(Object other) => identical(this, other) || | |
other is People && | |
runtimeType == other.runtimeType && | |
const ListEquality().equals(_people, other._people); | |
@override | |
int get hashCode => const ListEquality().hash(_people); | |
@override | |
String toString() => _people.toString(); | |
// You could also write your own list equality. Something close to this: | |
bool _listEquals<T>(List<T> a, List<T> b) { | |
if (a == null) | |
return b == null; | |
if (b == null || a.length != b.length) | |
return false; | |
if (identical(a, b)) | |
return true; | |
// Don't write this recursively, you might end up with space leaks. | |
// For more info on this, check out Tail Call Optimization (TCO). | |
for (int index = 0; index < a.length; index += 1) { | |
if (a[index] != b[index]) return false; | |
} | |
return true; | |
} | |
} | |
//------------------------------------------------------------------------------ | |
@immutable | |
class Person { | |
final String name; | |
const Person(this.name); | |
@override | |
bool operator ==(Object other) => | |
identical(this, other) || | |
other is Person && | |
runtimeType == other.runtimeType && | |
name == other.name; | |
@override | |
int get hashCode => name.hashCode; | |
@override | |
String toString() => "Person: $name"; | |
} | |
//------------------------------------------------------------------------------ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//------------------------------------------------------------------------------ | |
import "package:fast_immutable_collections/fast_immutable_collections.dart"; | |
//------------------------------------------------------------------------------ | |
//------------------------------------------------------------------------------ | |
void main() { | |
//---------------------------------------------------------------------------- | |
print("\n\n------------------------------------------------------------\n\n"); | |
//---------------------------------------------------------------------------- | |
//---------------------------------------------------------------------------- | |
// 1) This is ok. Immutability does work in this case. | |
// (This is covered in the `List.unmodifiable` docs.) | |
print("1) Direct Immutability\n\n"); | |
var list = [1, 2, 3]; | |
var unmodifiableList1 = List.unmodifiable(list); | |
list.add(4); | |
print("Original List: $list"); | |
print("Unmodifiable List 1: $unmodifiableList1"); | |
//---------------------------------------------------------------------------- | |
print("\n\n------------------------------------------------------------\n\n"); | |
//---------------------------------------------------------------------------- | |
// 2) This is not ok. Immutability doens't work because the nested elements | |
// are not themselves immutable. | |
// This is also covered in the `List.unmodifiable` docs.) | |
print("2) Nested Immutability\n\n"); | |
var list1 = [1, 2]; | |
var list2 = [1, 2, 3]; | |
var nestedList = [list1, list2]; | |
var unmodifiableList2 = List.unmodifiable(nestedList); | |
list1.add(10); | |
print("Original List 1: $list1"); | |
print("Original List 2: $list2"); | |
print("Unmodifiable List 2: $unmodifiableList2"); | |
//---------------------------------------------------------------------------- | |
print("\n\n------------------------------------------------------------\n\n"); | |
//---------------------------------------------------------------------------- | |
// 3) How would you modify, add, remove, etc. this `List.unmodifiable` object? | |
// FIC makes it much simpler and less error prone... | |
// And copying things to make changes will make `List.unmodifiable` | |
// unbearably slow. | |
print("3) Clunky modifications natively | FIC makes it easy!\n\n"); | |
var list3 = [1, 2, 3]; | |
var unmodifiableList3 = List.unmodifiable(list3); | |
var ilist3 = list3.lock; | |
var newUnmodifiableList3 = | |
List.unmodifiable(unmodifiableList3.toList()..add(4)); | |
var newIlist3 = ilist3.add(4); | |
print("New UnmodifiableList 3: $newUnmodifiableList3"); | |
print("New IList 3: $newIlist3"); | |
//---------------------------------------------------------------------------- | |
} | |
//------------------------------------------------------------------------------ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: fic_example | |
author: Philippe Fanaro <[email protected] | |
dependencies: | |
fast_immutable_collections: ^1.0.19 | |
collection: ^1.14.13 | |
meta: ^1.2.4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment