Open srawlins opened 1 year ago
Alternatively we could call this a false negative on prefer_collection_literals
. That is a lints:recommended lint rule, enforced internally as well, so that would require cleanup before landing.
Given that prefer_collection_literals
is intended to enforce the Effective Dart guideline, I'd much rather see it enhanced to cover this case than to see a new lint rule.
If there's a lot of cleanup that needs to be done, then I'd have to ask whether List.empty
ought to be covered by any lint at all.
And I would answer, 'yes'. 🤣
List.empty
was added because it allows you to do something that is otherwise difficult.
List.empty
is most useful in contexts where the type parameter depends on the environment, or the growable:
argument is not a constant. In other cases, the suggestion seems reasonable.
Counterexamples:
You can't use const <T>[]
in place of List<T>.empty()
when T
is a type variable.
Using const <Never>[]
in place of List<T>.empty()
is dangerous since result.toList()..add(thingOfTypeT)
will fail.
When switching to const []
, you have to ask yourself if the identity of the list object is important.
The growable
parameter may be e.g. a variable rather than a constant. In this case you can't choose between the suggested replacements.
List.empty(growable: growable)
with growable ? [] : const []
. It does not seem much of a readability improvement. Just keep the call.Ah that's really good context, @rakudrama . So maybe don't report if the constructor has a type variable as an explicit type argument, or when growable
is not a true
or false
literal.
When growable:
is false
, it is not whether the constructor call has an explicit type argument, but whether the type argument, explicit or inferred, contains type variables.
Consider
List<Set<T>> noSets<T>() => List.empty();
The inferred type argument to the constructor call is Set<T>
, which contains a type variable reference T
that makes the const
rewrite impossible.
But these would be a reasonable candidates because the inferred or explicit type arguments contain no type arguments:
List<Set<int>> noIntSets1() => List.empty();
List<Set<int>> noIntSets2() => List<Iterable<num>>.empty();
If growable:
is always true
, you can replace the constructor call with []
or <T>[]
regardless of whether there are type variables in the type argument.
Yep, that!
The List.empty
was introduced because I needed it during null-safety migration of the platform libraries, precisely for situations where growable
was variable.
There are other ways to do everything List.empty
does. Basically <T>[]
for growable and List<T>.generate(0, () => throw "unreachable", growable: false)
for non-growable. (Can't use List.filled
since it requires an actual value of the type, which you won't have.)
Using const
is not a replacement, for a number of reasons, the main one being that it doesn't work with type variables,
the second one is that it creates a list with a different underlying runtime type. That can introduce polymorphism in code which would otherwise be monomorphic.
I'm all for recommending you use []
or <T>[]
instead of List.empty(growable: true)
.
For growable:false
(the default), you should not recommend a replacement, using List.empty
should be the recommended way to get an empty fixed-length list.
Using const
, even when there is no type variable included, is not the recommened way.
I don't want users to start thinking "ooh, my type here is constant, so I can use const <T>[]
instead of List<T>.empty()
, but over here I cannot."
List.empty
, end of story. There is no corresponding literal. Const is something different, and we shouldn't mix concepts.[]
.List.empty
with a growable
parameter.
list_dot_empty
Or without the
dot_
, whatever.Description
Avoid using
List.empty
, introduced in Dart 2.9.Details
This constructor has one bool parameter,
growable
.List.empty(growable: false)
, you should instead use aconst []
list literal, for performance, and to follow the DO use collection literals when possible. Effective Dart guideline.List.empty(growable: true)
, you should instead use a[]
list literal, to follow the DO use collection literals when possible. Effective Dart guideline.It appears the existing
prefer_collection_literals
lint does not flagList.empty
(at least there are no tests).Kind
Style and performance.
Good Examples
Bad Examples
Discussion
This came up in an internal readability discussion.
Discussion checklist