This is not particularly well-thought-out, and requires a lot of stuff we don’t have, but it’s super cool.
Summary
Make remove, get, and get_mut accept ranges, and insert accept IntoIterators. Deprecate iter, iter_mut, clear, drain, and, truncate in favour of these.
That is:
-
foo.clear(); -> foo.remove(..);
-
foo.truncate(a); -> foo.remove(a..);
-
let iter = foo.drain(); -> let iter = foo.remove(..);
-
let iter = foo.iter(); -> let iter = foo.get(..);
-
let iter = foo.iter_mut(); -> foo.get_mut(..);
Additional interesting patterns include:
-
foo.insert(i, some_iterable) inserts all of the elements of the iterable at the given index. This suggests some simple patterns like foo.insert(i, vec![1,2,3,4]), and some weird patterns like inserting an Option unconditionally to “maybe” insert.
-
foo.remove(a..b) gets a drain over an arbitrary subrange, performing the back-shift and length change only when the iterator is dropped.
-
foo.get_mut(a..b) get an arbitrary subrange iterator. Combined with insert this allows arbitrary subranges to be replaced with arbitrary subranges effeciently and cleanly.
Note that remove, insert, and get would continue to provide the same behaviour for integer indexing. This implies that we add some kind of trait for each of these with associated returns types, and implement them for the appropriate inputs, just like Index.
Also note that things like HashMap would not be able to accept arbitrary subranges. Only indices and Full ranges. Also Sorted collections still would like to have range methods for all the inclusive/exclusive combinations.
An interesting side-effect is that remove(i...i).next() is a “non-panicking” remove on a single index (here using a hypothetical inclusive range syntax with 3 dots).
As far as I can tell, there should be no perf regressions by moving to this more condensed iterator-returning form, as e.g. truncate and clear need to iterate the collection anyway to drop the elements, and the different variants should be statically dispatched to.
Requirements
Good to Have