Reputation: 631
Let's say you're managing the list of serial numbers of the bicycles owned by residents in your building, with the objective of planning ahead to build additional safe bike storage.
Some people will of course have no bikes.
In Dart > 2.12 (with null safety) you could
use a non-nullable List<String>
and initialize it to an empty list
class Resident {
String name;
List<String> bicycles = [];
}
or you could use a nullable List<String>
and use null
as a flag to signal that someone has no bikes.
class Resident {
String name;
List<String>? bicycles;
}
Both designs are of course workable, but does it turn out down the road that one is clearly better than the other—more idiomatic to the new Dart, for example? In other words, what's better, an initially empty non-nullable or an initially nullable and null container?
Even if I count the bits needed, it's not quite clear. There would be wasted storage to construct an empty list in the first case, but there is also storage wasted in the second case—though it's of an unknown, and perhaps implementation dependent—amount.
Upvotes: 1
Views: 66
Reputation: 90115
If you want to represent having none of something, then prefer non-nullable container types with an empty state to nullable types.
null
everywhere.
Meanwhile, dealing with an empty container often doesn't involve any extra work. Contrast:
// Nullable case.
final bicycles = resident.bicycles;
if (bicycles != null) {
for (var bicycle in bicycles) {
doSomething(bicycle);
}
}
with
/// Non-nullable case.
for (var bicycle in resident.bicycles) {
doSomething(bicycle);
}
null
when the container becomes empty so that there aren't two cases to deal with, but as noted above, the empty case often is free anyway, so that'd be more work for usually no gain. Furthermore, resetting references can be a lot of extra work:
var list = [1, 2, 3];
mutateList(list);
if (list.isEmpty) {
list = null;
}
If mutateList
could remove elements from list
, then every caller would need to do extra work to replace empty List
s to null
.null
, you'd still have different behaviors when transitioning to a non-empty container. Consider:
var sam = Resident();
var samsBicycles = sam.bicycles;
sam.addBicycle();
What would you expect samsBicycles
to be? If Resident.bicycles
is initially null
, then samsBicycles
will remain null
and will no longer refer to the same object as sam.bicycles
.Upvotes: 2