Just opened up a request for adding support for an Undefined type
github.com/dart-lang/sdk/issues/40921Posted Mar 7, 2020, 10:48 PM UTC
Posted Mar 7, 2020, 10:48 PM UTC
In your use case example, what's wrong with not using the ??? If null is a valid value, then let it be a valid value and treat it as such.
Because when you use copyWith and don't set a parameter because you're not trying to change that value, it gets set to null.
for example given the copyWith function definition is as follows:
MapState copyWith({p1, p2}){...}
if you call state.copyWith(p2: someVal), then p1 is null and is told to grab its existing value.
Example 2:bool someBool = null;state.copyWith(p1: someBool, p2: someVal)
This will return the same result as Example 1, because both times, the variable is null. There's no way to set a variable to null with a function like this.What I ended up doing was writing a `setAsNull` function:
MapState setAsNull({
bool activeTopCategory = false,
bool activeCategory = false,
}) {
return MapState(
activeTopCategory: activeTopCategory ? null : this.activeTopCategory,
activeCategory: activeCategory ? null : this.activeCategory,
topCategories: topCategories,
categories: categories,
subCategories: subCategories,
isCardOpen: isCardOpen,
);
}
Then maybe a generic copyWith method isn't the way to go for how you're using the object.
I'm partially against adding something like undefined because most languages are moving away from null-like values being a given, even Dart is going NNDB.
Going back to the example, it could be done with a copy and using setters which would look something like
final instanceB = instanceA.copy()
..field1 = null
..field2 = 5;
Where copy creates a new instance of the object with the exact same values (leaving out deep copying for now).
EDIT: Was typing the above on my phone so it was a little uncomfortable.
The better solution in my opinion is to have a rich model with methods that perform exactly what you want, as opposed to generic ones like copyWith and copy from my example. If the object was a model for a shipment order, possible methods could be
class Order {
// fields
// implementation omitted
void addItem(Item i);
void approve(String by);
void unapprove();
}
It's a bit of a contrived example but I don't have a better domain model in mind right now. For Order.items, it should never be null, whereas the approval fields can be, and they are valid values. And rather than doing orderInstance.copyWith(approvedBy: null, approvedOn: null) to reverse the approval, it can just be orderInstance.unapprove(). Users of the object doesn't need to know which fields need to be set/unset, they would know that the order can be approved and then reversed. If you want to create a new instance for every operation, change the void return type to Order.
Thanks. I saw a library that generates code like this. However this doesn't work when working with immutable objects since you can't have setters. I've been working with inmutables for a while now and I feel they're safer
If you're into generated code, could look into built_value. They're able to handle updates to the immutable values through a rebuild method. Haven't looked into whether that then accepts null values by default.
Undefined is a boulder we have carry everywhere. Just like null.
We'll soon get Non-Nullable-By-Default, I don't wanna wait for Non-Undefined-By-Default.
As someone commented on the request, Union Types are the way to go!
Ok, how would that fit the use case?
I'm surprised I couldn't find a previous ticket on this.