none_or library
Provides a new typedef NoneOr<T> and a new class None<T> to enable
differentiation between explicit values given to a field that may be null
versus providing no value to a field. Expected use case is for copyWith
functions.
NOTE: There is no underlying difference in the compiler between NoneOr
Why?
Dart lacks Union Types:
String? | None value; // This is NOT valid dart code!
However, there are times, such as with copyWith() functions where there may
actually be a difference between an explicit null and an implicit
(default) value. For example:
MyClass<int> c0 = MyClass(field: 0); // c0.field = 0
MyClass<int> c1 = c0.copyWith(); // c0.field = 0
MyClass<int> c2 = c0.copyWith(field: null); // c0.field = 0 // <- WRONG
It is potentially undesirable to have c2.field == 0 when the intent may
have been to overwrite c2.field == null. Unfortunately, due to the
dart-imposed restriction that:
It is a compile-time error for any class to extend, mix in or implement
`FutureOr`.
together with NO other support of any kind for Union Types, makes it
impossible to differentiate between implicit(/default) null and explicit
null without tedious wrapper classes that are unacceptable from a
developer perspective.
By using NoneOr<T?> for any nullable field in an object with a copyWith
function in conjunction with the defaulted const None() type as the
implicit(/default) value for the field(s) you enable developers for your
API to simply pass in null to force-remove the field, a non-null T to
overwrite the field, or pass in None() (or omit the field alltogether) to
keep the value as is.
None
A None<T> value represents no desired change in a nullable value T?.
It has nothing to do with Future
The primary power of the None
None.fallback
Given a primary value of FutureOr
The intended usecase is for copyWith functions:
MyClass copyWith({
NoneOr<T>? nullableField = const None(),
Y? nonNullableField,
// ...
}) => MyClass(
nullableField: None.fallback(nullableField, this.nullableField),
nonNullableField: nonNullableField ?? this.nonNullableField,
// ...
);