What is the practical difference between `List.cast` and `List.from` for upcasting a List?

43 views
Skip to first unread message

Mateus Felipe Cordeiro Caetano Pinto

unread,
Sep 3, 2021, 10:21:32 AM9/3/21
to Dart Misc
The context here is for list downcasting.

The obvious difference between them is that `.cast` does not make another list, but a view of the list with the specified type.

However, why would I use one or another? In other words:
  • What are the use cases for using a view on a list instead of an entire new list of the desired type?
  • Is there difference in performance? In a code review, a coworker of mine said that I should use `List.from` or `List.of` instead of `List.cast` (although we shouldn't really use `List.of`, according to this commentary).

Looking for some guidance I found these two sources:

Thanks, in advance.

William Hesse

unread,
Sep 3, 2021, 11:13:13 AM9/3/21
to mi...@dartlang.org
If you are asking about upcasting a List<B> to a List<A>, where B is a subclass of A, then
the List.cast method will not make a copy of the List<B>, but will make a view of it that has type List<A>.
But you can never assign an element of type A to this view, unless it actually is of type B, because it needs to be stored in the underlying List<B>.

The List.of, List.from, and literal constructors will all construct a new list, and should be closely equivalent in performance.
List.of could potentially skip a check that each element is an A when copying it, because List.of knows that its input only has elements of type B, which is an A.
The literal constructor would also know this.
I would suggest the literal constructor
<A>[ ...myListB ]

Using List.cast lets you avoid creating a new object, and copying all the elements of your list to the new object.  This could be expensive if the list is big.

I don't know what you mean by "The context here is for list downcasting".  Are you asking about list upcasting or list downcasting?

In many cases, you should not need to upcast a List<B> to a List<A> - because of covariant generic subtyping, a List<B> is a List<A>: List<B> is a subtype of List<A>.
A List<B> can be used directly anywhere a List<A> can, except that assigning a non-B element to it will be a run-time error. 
This is exactly the situation where you really need to make a new List<A> that is a copy of the elements of your List<B>.




--
For more ways to connect visit https://dart.dev/community
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.
To view this discussion on the web visit https://groups.google.com/a/dartlang.org/d/msgid/misc/52a2990b-36da-4e1e-8711-93f0e8506c17n%40dartlang.org.


--

       - William Hesse

William Hesse

unread,
Sep 8, 2021, 3:19:57 AM9/8/21
to mi...@dartlang.org
If the use of your downcasted list is simple, just reading through the elements a few times, or accessing some of them, then .cast is good, because it just checks the type on each read of an element.
If you will be saving this downcasted list, and using it many times or iterating through it many times, then List.from is better.  It creates a new list of the correct type, filled with the elements in the input list.
Because the code you pass this list to will know the static type of its input is List<MyModel>, it will not need to do any type checks (or null checks) when reading elements from it.

In most cases the performance difference of the two will not be significant.
If you plan to read through the downcasted list hundreds of times then List.from is much better
If it is a big list, and you will only ever read a few items out of the downcasted list, not the whole thing, then .cast would be much better.
In all other cases, there won't be a big difference, and it won't matter which you use.

If you did not know that all elements of your List<Object?> were non-null MyModel objects, then list.whereType<MyModel>().toList() would give you a new List<MyModel> containing only the elements that are of type MyModel.

--

       - William Hesse

Mateus Felipe Cordeiro Caetano Pinto

unread,
Sep 8, 2021, 9:54:05 AM9/8/21
to Dart Misc, William Hesse
Thanks, William, that clears out the question!
Reply all
Reply to author
Forward
0 new messages