Currently ForEach accepts an iterator, and it needs to own that iterator. This means that under many circumstances the entire array is cloned; worse, it gets copied twice (once when passed as a parameter to ForEach, and a second time internally within ForEach when the iterator is actually iterated).
It's possible that there may be a more efficient approach that involves fewer clones; I'm not sure if this is possible or not. Here are some facts about ForEach:
The iterator passed to ForEach is only iterated once. This may seem counterintuitive, but Views are transient objects with relatively short lifetimes; each rebuild() creates a new View with a new iterator instance.
The iterator is consumed by the ForEach view during rebuild.
The lifetime of the iterator is longer than the create() function, but not much longer. During a rebuild, create() is called to produce a view hierarchy; the result of that call is immediately used, either for .build() or .rebuild(). Afterwards the view is dropped. So the lifetime of the iterator needs to be slightly longer than the create() call.
However, ForEach nodes sometimes live longer, although these longer-lived instances never call the iterator. Some View instances are kept around for purposes of cleanup, so that we can call .raze() on the view. The .raze() method only despawns the child instances that already exist; the iterator is not called. Nevertheless, the ForEach instance still holds on to the iterator because it's a property of the struct.
ForEach loops can work with ranges, e.g. ForEach(0..10, etc.). This functionality should be preserved for backwards compatibility.
Currently
ForEach
accepts an iterator, and it needs to own that iterator. This means that under many circumstances the entire array is cloned; worse, it gets copied twice (once when passed as a parameter to ForEach, and a second time internally within ForEach when the iterator is actually iterated).It's possible that there may be a more efficient approach that involves fewer clones; I'm not sure if this is possible or not. Here are some facts about
ForEach
:ForEach
is only iterated once. This may seem counterintuitive, butViews
are transient objects with relatively short lifetimes; each rebuild() creates a newView
with a new iterator instance.ForEach
view during rebuild.create()
function, but not much longer. During a rebuild,create()
is called to produce a view hierarchy; the result of that call is immediately used, either for.build()
or.rebuild()
. Afterwards the view is dropped. So the lifetime of the iterator needs to be slightly longer than thecreate()
call.ForEach
nodes sometimes live longer, although these longer-lived instances never call the iterator. Some View instances are kept around for purposes of cleanup, so that we can call.raze()
on the view. The.raze()
method only despawns the child instances that already exist; the iterator is not called. Nevertheless, theForEach
instance still holds on to the iterator because it's a property of the struct.ForEach
loops can work with ranges, e.g.ForEach(0..10, etc.)
. This functionality should be preserved for backwards compatibility.