Home > front end >  Why doesn't type casting List<Widget?> as List<Widget> work if we remove all nulls
Why doesn't type casting List<Widget?> as List<Widget> work if we remove all nulls

Time:04-08

Option A: not working

var a = <Widget?>[Container(), null];
a.removeNulls(); 
print(a.length == 1 && a[0] != null) // true
var b = a as List<Widget>; // _CastError (type 'List<Widget?>' is not a subtype of type 'List<Widget>' in type cast)

Option B: working

var a = <Widget?>[Container(), null];
a = a.whereType<Widget>().toList(); 
var b = a as List<Widget>; // works fine

.removeNull() is part of fast_immutable_collections

CodePudding user response:

I'm not familiar with the package, but quickly looking up the extension method shows that's just a wrapper over another function, removeWhere, which has nothing to do with nullability.

Try print(a.runtimeType) and you'll see List<Widget?>. Thus, error thrown is correct.

As to why it is the case with the library, only the owner can answer that.

CodePudding user response:

A cast with as treats as object as a different type. It does not mutate the object or create a new object.

Suppose that you could cast List<T?> as List<T> for a non-nullable type T. For example:

var a = <int?>[0, 1, 2];
var b = a as List<int>; // Pretend that this is legal.

now b and a refer to the same List object. But then consider:

a.add(null); // Legal. `a` is `List<int?>` and can accept `null`.
var last = b.last; // ???

Now you have a situation where b.last would refer to a null element even though b claims to be a List of non-nullable elements. Just because a did not have null elements at the time you casted it does not mean that it will not have null elements in the future.

What you instead must do is to create a new List object (e.g. with whereType<T>().toList()) or must create a new List-like object that performs runtime casts for each element (which is what List.cast does).

  • Related