I just had a random thought: a common pattern in Rust is to things such as:
let vec_a: Vec<String> = /* ... */;
let vec_b: Vec<String> = vec_a.into_iter().filter(some_filter).collect();
Usually, we need to be aware of the fact that Iterator::collect()
allocates for the container we are collecting into. But in the snippet above, we’ve consumed a container of the same type. And since Rust has full ownership of the vector, in theory the memory allocated by vec_a
could be reused to store the collected results of vec_b
, meaning everything could be done in-place and no additional allocation is necessary.
It’s a highly specific optimization though, so I wonder if such a thing has been implemented in the Rust compiler. Anybody who has an idea about this?
Is it really fair to say retain doesn’t compose as well just because it requires reference-based update instead of move-based? I also think using move semantics for in-place updates makes it harder to optimise things like a single field being updated on a large struct.
It also seems harsh to say iterators aren’t a zero-cost abstraction if they miss an optimisation that falls outside what the API promises. It’s natural to expect
collect
to allocate, no?But I’m only writing this because I wonder if I haven’t understood your point fully.
(Side note: I think you could implement the API you want on top of
retain_mut
by usingstd::mem::replace
with a default value, but you’d be hoping that the compiler optimises away all thereplace
calls when it inlines and sees the code can’t panic. Idk if that would actually work.)