I generally find that the functions on std::vec::Vec are somewhat inconsistent. Before considering to propose any changes to this, I want to find out if people agree that it’s not quite perfect… Also, had there been a discussion of this already and whether DST may affect this in any significant way?
Vec inconsistent to what?
Vec is one-of-a-kind type in Rust after all.
Being less vague by providing examples of the inconsistencies would help people provide feedback.
Apologies for being vague.
From the top down:
grow- takes a slice… why it cannot take a
tailn- return a slice… why there is no version that would return a
Vec? and how about
last- why there is no
push_all- again, only takes a slice
init- don’t even understand why this function is needed and why it’s call so… and again it does return a slice, not a
Other counterintuitive naming choices are
From this it doesn’t seem like
Vec is an immutable sort of structure, I’d much rather like to see something close to Clojure, or otherwise something more minimal, like with Python list you only have:
sort - and that’s rather enough. I understand that Rust is not dynamic, growing would be an addition to the above, but otherwise I’m pretty confused by the set of methods a
growdoesn’t take a slice, it takes a reference.
Vecbecause they create a view into the last elements of a vector. To convert a slice to a vector, use
- I don’t know why there is no
first. (Something makes me think that this may have been removed recently.) That seems like it could be a reasonable addition, but it would be much more useful to have a method that returns
Option<&'a T>for any index.
push_alltakes a slice because slices are much more useful than
Vecs for pasing to functions. Any
Veccan be converted to a slice, but converting from a slice to a
Veccan be an expensive operation, as it has to allocate.
initprobably comes from languages like Haskell, where that is the standard name for such a method.
tailetc. can be used quite a lot in functional programming to do with lists. It returns a slice for the same reason
taildoes (see above).
All these methods are here to remove commonly-seen boilerplate code to do with lists. It’s significantly nicer to use
std::os::args().tail() to get the command-line arguments passed to your program than
std::os::args().slice_from(1) or even
let args = std::os::args(); args.slice(1, args.len()).
Eh, I feel like
args().slice_from(1) is almost better, since I can read it and know immediately what it does.
tail is more ambiguous.
Most of the methods you list there on
Vec are for ergonomic reasons, to avoid having to write the
some_vec.as_slice().foo() so much (by putting the common ones directly on
Vec). With DST we can likely remove them and instead have a
Deref<[T]> for Vec<T> implementation, which will allow the
&[T] methods to be called automatically without being explicitly part of the
Vec API (although you may not regard this as a good thing).
Vec from all those functions would be really really inefficient. Returning a slice is just returning a pointer into the memory owned by the
Vec, but returning a
Vec would require allocating new memory and cloning everything (or consuming the old
Vec and shifting pointers/byte-copying data around, which is still inefficient, especially for
tail). This slow behaviour copy-ful can be achieved with
first is easily implemented as
x (well, really, if/when we move
get to return an
last is more complicated/annoying/easier to get wrong:
x.get(x.len() - 1).
In what way are
.push_all_move which takes a
Vec, both are somewhat useful, they can (and possibly should) be removed in favour of the more flexible
v.extend(slice.iter().map(|x| x.clone())); v.extend(vec.move_iter())
We would still need some form of mutable
Vec. It’s a equivalent to C++'s
std::vector (and can be more efficient due to Rust not having copy constructors!), with essentially the same functionality, as a (somewhat) general purpose sequence container that other structures can be built on (e.g.
PriorityQueue and (previously)
HashMap). An efficient immutable/persistent vector type is a different data structure, it is desirable but not a replacement for
I agree that the
Vec API could use some adjustment/trimming (although I weakly recommend we wait until after DST before embarking in earnest), but having the ‘flavourful’ methods is nice, as you don’t have to write (and debug) them when you do need them. And if necessary, they can be optimised using
unsafe code by the top Rust experts (with code-review by other top Rust experts); I think it’s a reasonable statement that
unsafe code outside
rust-lang/rust is less likely to be correct, on average.
(Another approach we could/should investigate is seeing if we can turn some of the
Vec algorithms into more generic
Iterator ones, similar to C++.)
On Fri, Aug 01, 2014 at 10:27:38PM +0000, errordeveloper wrote: