What's the best way to clone a List?

157 views
Skip to first unread message

Alexandre Ardhuin

unread,
Jun 26, 2019, 4:07:59 AM6/26/19
to General Dart Discussion
Given an existing list `list`, what's the best way to copy this list as a new list ?

I can think of several options (not an exhaustive list)

1. `List.from(list)`
2. `List.of(list)`
3. `[...list]`
4. `list.toList()`

Is there a specific answer depending on the targetted plateform ?

Alexandre

John McMahon

unread,
Jun 26, 2019, 9:37:59 AM6/26/19
to Dart Misc
What matters to you? performance? Ensuring they are a copy and not copying by reference?

What defines "best" for your use case?

Alexandre Ardhuin

unread,
Jun 26, 2019, 9:55:34 AM6/26/19
to General Dart Discussion
I meant simple copy (not deep).

All the proposals I maid do the same think : create a new list with the same elements.

Alexandre

--
For more ways to connect visit https://www.dartlang.org/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/a1bb3c5f-9007-4c2b-bf36-0cc31fca0a94%40dartlang.org.

Lasse R.H. Nielsen

unread,
Jun 26, 2019, 2:12:43 PM6/26/19
to mi...@dartlang.org
I'd use list.toList(). It knows everything about the list it is going to make a copy of, so it should be the most performant version possible. It's readable and idiomatic.

Maybe use [...list] if you find it more readable, and don't care about performance. It should still be relatively performant, but it needs to be prepared for any object implementing `Iterable`, so there will be some testing and probing to find the most performant algorithm, before it can get to executing it.

Only use `List.from` when you want to change the element type of the list to something that is not a super-type.
Changing it to a supertype can be done using <SuperType>[...list] (for now it can also do down-casts, but that'll likely stop working with NNBD and the removal of implicit downcasts).

Never use List.of, it's basically subsumed by the new list literal.

/L



--
Lasse R.H. Nielsen - l...@google.com  
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 København K - Denmark - CVR nr. 28 86 69 84

Alexandre Ardhuin

unread,
Jun 27, 2019, 5:07:45 AM6/27/19
to General Dart Discussion

Natalie Weizenbaum

unread,
Jun 27, 2019, 3:29:46 PM6/27/19
to General Dart Discussion
Why would [...list] be any less performant than list.toList()? Both of them have to work with Iterable as well as List, and both could in principle be optimized if list is statically known to already be a List.

I personally prefer List.of(). It may be slightly less performant, but it's predictable in that you always know exactly what type of list you're getting—you don't run the risk of potentially getting passed a weird custom List whose toList() also returns a weird custom List. I generally value predictable edge-case behavior over slight performance edges. ([...list] is also predictable, but I prefer words to punctuation where equivalent).


Lasse R.H. Nielsen

unread,
Jun 28, 2019, 1:22:13 AM6/28/19
to mi...@dartlang.org
On Thu, Jun 27, 2019 at 9:29 PM 'Natalie Weizenbaum' via Dart Misc <mi...@dartlang.org> wrote:
Why would [...list] be any less performant than list.toList()? Both of them have to work with Iterable as well as List, and both could in principle be optimized if list is statically known to already be a List.

The list.toList() doesn't have to work with both Iterable and List, because each individual toList implementation knows which class it is defined on. If a class implements List but uses the toList from IterableBase, then it is less efficient than possible, and it should be using ListBase.

The [...list] syntax doesn't know the type of list in general. The compiler might be able to recognize that the list is actually a platform list, and then it can convert this directly to list.toList(). You just cannot assume that to be the case. The implementation can optimize based on the run-time type of the list, but that requires checking the type. For the VM, that's probably fairly efficient (just comparing the class-ID to a number of integers), but dart2js will have to check the JS object's type (maybe JSArray is easy to detect, then perhaps that can be efficient too). In any case, you are using a general feature to work on a list from the outside instead of letting the list itself do the work from the inside. The latter always has more information easily available.


I personally prefer List.of(). It may be slightly less performant, but it's predictable in that you always know exactly what type of list you're getting—you don't run the risk of potentially getting passed a weird custom List whose toList() also returns a weird custom List. I generally value predictable edge-case behavior over slight performance edges. ([...list] is also predictable, but I prefer words to punctuation where equivalent).

There is an argument for using a constructor or literal because it generates a known type. It might even improve static analysis on the uses of the new list.

Implementations of toList should not return any weird lists, though. Even Uint8List.toList returns a normal list. Still, since the method is overridable, there is now way to promise that no class will do something different.

/L
 
Reply all
Reply to author
Forward
0 new messages