Skip to content

Instantly share code, notes, and snippets.

@nythrox
Created April 4, 2021 16:35
Show Gist options
  • Save nythrox/f2f59bfdefc22e3ae3c2ac05a0cf37a3 to your computer and use it in GitHub Desktop.
Save nythrox/f2f59bfdefc22e3ae3c2ac05a0cf37a3 to your computer and use it in GitHub Desktop.
Automatic Immutability in Dart using noSuchMethod() with no build_runner
main() {
setupImmutable(() => User());
final user1 = create(User()
..name = "uwu"
..age = 100);
final user2 = copy(user1..name = "owo"..child = User());
final user3 = copy(user2..name = "eheh");
}
abstract class _User {
String name;
int age;
User child;
}
class User extends Immutable<User> implements _User {}
class Change {
final dynamic key;
final dynamic value;
const Change(this.key, this.value);
}
final instanciations = <Type, dynamic Function()>{};
void setupImmutable<T>(T Function() setup) {
instanciations[T] = setup;
}
T instanciate<T>(Type type) {
return instanciations[type]();
}
class Immutable<T extends Immutable<dynamic>> {
Map<String, dynamic> _values = {};
List<Change> _changes = [];
@override
noSuchMethod(Invocation invocation) {
print(invocation.runtimeType);
print(invocation.memberName);
final name = getName(invocation.memberName);
if (invocation.isGetter) {
return _values[name];
}
if (invocation.isSetter) {
_changes.add(Change(name, invocation.positionalArguments.first));
return;
}
if (invocation.isMethod) {
return Function.apply(
_values[name],
invocation.positionalArguments,
invocation.namedArguments,
);
}
}
// T merge(T other) {}
T copyChangesTo(T instance) {
instance._values = {..._values};
_changes.forEach((change) {
instance._values[change.key] = change.value;
});
return instance;
}
T copy<T extends Immutable>(T changed) {
return copyChangesTo(changed as dynamic) as dynamic;
}
T copyFrom<T extends Immutable>(T changed) {
return changed.copy(this) as dynamic;
}
// @override
// bool operator ==(Object other) {
// if (other is Immutable<T>) {
// return DeepCollectionEquality().equals(_values, other._values);
// }
// return false;
// }
// @override
// int get hashCode => DeepCollectionEquality().hash(_values);
}
T create<T extends Immutable>(T value) {
return value.copyChangesTo(value);
}
T copy<T extends Immutable>(T from) {
final newInstance = instanciate(T);
return newInstance.copyFrom(from);
}
final _create = create;
String getName(Symbol s) {
String text = s.toString().replaceFirst("Symbol", "");
text = text.replaceAll("(", "");
text = text.replaceAll(")", "");
text = text.replaceAll("=", "");
text = text.replaceAll('"', "");
text = text.replaceAll('"', "");
return text;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment