Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collections Reform Part 2 #509

Merged
merged 2 commits into from
Dec 18, 2014
Merged

Collections Reform Part 2 #509

merged 2 commits into from
Dec 18, 2014

Conversation

Gankra
Copy link
Contributor

@Gankra Gankra commented Dec 9, 2014

This RFC shores up the finer details of collections reform. In particular, where the previous RFC
focused on general conventions and patterns, this RFC focuses on specific APIs. It also patches
up any errors that were found during implementation of part 1. Some of these changes
have already been implemented, and simply need to be ratified.

rendered

@Gankra
Copy link
Contributor Author

Gankra commented Dec 9, 2014

CC @aturon @reem @huonw @cmr @pcwalton @nodakai @bfops

One of your desired collections items may have arrived in this RFC.

@arielb1
Copy link
Contributor

arielb1 commented Dec 9, 2014

We can do append by just having a Vec::<T>::clear_into_iter::<'a>(&'a mut self) -> MoveItems<T>+'a that sets len to 0. If we want to hack performance we can do it by branching on TypeId, or equivalently on the return value of Any – see http://is.gd/6bznhA (LLVM optimizes this out).

```
/// Gets a slice over all the elements in the RingBuf. This may require shifting
/// all the elements to make this possible.
pub fn to_slice(&'a self) -> &'a [T]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn’t this require &mut self to allow shifting the elements inside?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, yes.

@aliblong
Copy link

aliblong commented Dec 9, 2014

I prefer reserve_index for VecMap at least. In the example given in the documentation, where a VecMap maps month names to numbers, my thought process would be "How many months are there? 12! So I want to reserve 12 in this VecMap". It would feel clumsy to have to reserve 13, especially given that 0-indexing has taught my brain to think in n-1 with collections.

It's also important to note that whatever design we choose should be mirrored in with_capacity.


* Stabilize `front`/`back`/`front_mut`/`back_mut` for peeking on the ends of Deques

* Explicitly specify HashMap's iterators to be non-deterministic between iterations. This would
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this is hacking around the fact that there are types that want to implement ExactSizeIterator but not DoubleEndedIterator. Why don't we clean up that API?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most things that care about ExactSize also care about DoubleEnded, so I'm not sure if that's totally helpful. I agree that it's a borderline abuse to impl DoubleEnded on an "unordered" sequence, though.

@aturon
Copy link
Member

aturon commented Dec 11, 2014

Passing thought: should with_capacity on e.g. VecMap be renamed as well?

@aliblong
Copy link

Perhaps rename with_capacity to with_reserved_index for VecMap? A bit verbose, but fits nicely with reserve_index.

@tbu-
Copy link
Contributor

tbu- commented Dec 11, 2014

With the PR rust#19715 I raised the question whether VecMap (and consequently Bitv, TrieMap as @gankro pointed out) should have a type parameter for the key type. As this lets us add more possible index types in a backward-compatible fashion, I'm very much for it. Could that be added to this RFC?

based around the largest index they have set, and not the number of elements they contain.
One could instead opt for `reserve_len` or
`reserve_capacity`, which are effectively the same method, but with an off-by-one. That is,
`reserve_len(x)` == reserve_index(x - 1)`. `reserve_len` would have the benefit of returning the
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a nitpicking; markup error here.

`reserve_len(x)` == reserve_index(x - 1)`

@Gankra
Copy link
Contributor Author

Gankra commented Dec 12, 2014

@aturon And I sat down this afternoon and played a little marry/murder/make-out with libcollections. As a result major update:

  • RFC now recommends stabilization/removal paths for all collections
  • RFC now deprecates some Vec and DList methods
  • split_at -> split_off
  • reserve_len wins
  • -> (&[T], &[T]) wins for RingBuf::as_slices

///
/// Calls either `grow()` or `truncate()` depending on whether `new_len`
/// is larger than the current value of `len()` or not.
pub fn resize(&mut self, new_len: uint, value: T) where T: Clone
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, could you explain a little more the rationale for including this convenience method? I'm not sure I've personally ever needed it, but I may just be in a different line of work!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something a few people has asked for. I don't have a strong desire/motivation for it, but I thought I would give it a fair try out in this RFC.

Asked for in rust-lang/rust#19104 (comment)

so maybe @nodakai can give a better justification.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok, I may be forgetting, but do we have a number of other convenience methods like this on collections? I thought we had pared it back to a fairly bare-bones sense.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If one wants to ensure that a vector is exactly 10 items long, this is the best method to call since it will work right even if the vector is currently 9 or 11 items long.

IMO grow and truncate are the convenience methods, not resize.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be worth looking at what the C++ std::vector provides: http://en.cppreference.com/w/cpp/container/vector

(Spoiler: It's only resize.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Valloric But growing and shrinking really are very different operations. resize necessarily must branch on whether to grow or shrink, whereas grow and truncate don't.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Valloric it would be difficult to remove truncate as you can't always manifest a T to call resize to truncate. C++ looks like it leverages overloading as well to provide some more functionality which we may not be able to match exactly.

@alexcrichton
Copy link
Member

This looks awesome @gankro, nice work!

@Gankra
Copy link
Contributor Author

Gankra commented Dec 13, 2014

@thestinger: for the sake of transparency, I feel obligated to notify you that the current draft of this RFC is recommending the removal of Tree*, Trie*, LruCache, bitflags!, and EnumSet from the standard library. I believe you were opposed to this in the past.

* Unstable: Bitv, BitvSet, VecMap
* Move to [collect-rs](https://github.com/Gankro/collect-rs/) for incubation:
EnumSet, bitflags!, LruCache, TreeMap, TreeSet, TrieMap, TrieSet

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think DList is ready? It's unclear if it is near its final form.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And why do you think bitflags isn't ready? I agree about other collections.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collections Reform 1 already proposed cutting out a lot of DList's methods, so it's going to have a pretty minimal/uncontroversial interface.

As for bitflags, I'll leave that to @aturon

Add drain, and link to WIP implementations.
@Gankra
Copy link
Contributor Author

Gankra commented Dec 17, 2014

Added a drain iterator for moving out of an &mut Collection without wasting the allocation.

alexcrichton added a commit to alexcrichton/rust that referenced this pull request Dec 22, 2014
This pull request:

*Renames `BinaryHeap::top` to `BinaryHeap::peek`
*Stabilizes `front/back/front_mut/back_mut` in `DList` and `RingBuf`
*Stabilizes `swap` in `RingBuf`

in accordance with rust-lang/rfcs#509.

Note that this PR does not address `Bitv::{get,set}` or HashMap's iterators, nor does it move `std::vec` to `std::collections::vec`, all of which still need to be done.

Because of the method renaming, this is a [breaking-change].
@bluss
Copy link
Member

bluss commented Dec 24, 2014

What did you intend w.r.t ExactSizeIterator and DoubleEndedIterator? I'm against implementing traits just because it's possible, with the hash maps and sets it doesn't seem useful at all. Maybe ExactSizeIterator on its own if it is untangled from DEI, but even there I don't really know any real use.

bors added a commit to rust-lang/rust that referenced this pull request Dec 27, 2014
Implement `reserve_len` and `reserve_len_exact` for `VecMap` in accordance with rust-lang/rfcs#509.
bors added a commit to rust-lang/rust that referenced this pull request Dec 28, 2014
This PR deprecates the `DList::ListInsertion` trait, in accordance with rust-lang/rfcs#509.  The functions which were previously part of the ListInsertion impl for `DList::IterMut` have been moved to be inherent methods on the iterator itself, and appropriate doctests have been added.
aturon added a commit to aturon/rust that referenced this pull request Dec 30, 2014
This commit takes a second pass through the `vec` module to
stabilize its API. The changes are as follows:

**Stable**:

* `dedup`
* `from_raw_parts`
* `insert`
* `into_iter`
* `is_empty`
* `remove`
* `reserve_exact`
* `reserve`
* `retain`
* `swap_remove`
* `truncate`

**Deprecated**:

* `from_fn`, `from_elem`, `grow_fn` and `grow`, all deprecated in
  favor of iterators. See rust-lang/rfcs#509

* `partition`, `partitioned`, deprecated in favor of a new, more
  general iterator consumer called `partition`.

* `unzip`, deprecated in favor of a new, more general iterator
  consumer called `unzip`.

A few remaining methods are left at experimental status.

[breaking-change]
@bluss
Copy link
Member

bluss commented Jan 2, 2015

Is it possible to amend the RFC to keep .merge() on DList? It seems absurd to add new "allocation-free" method to DList while removing others like .merge(). I'm mostly confused by the cluelessness of the deprecation message "Use other methods on IterMut"; it would be better to be more honest and tell the user there is no replacement.

@Gankra
Copy link
Contributor Author

Gankra commented Jan 2, 2015

I assure you merge was never allocation free; it just used IterMut.

@Gankra
Copy link
Contributor Author

Gankra commented Jan 2, 2015

Oh no wait, it totally did! I misread the source.

bors added a commit to rust-lang/rust that referenced this pull request Jan 11, 2015
Implements the `append()` and `split_off()` methods proposed by the collections reform part 2 RFC.

RFC: rust-lang/rfcs#509
Tracking issue: #19986
@sandeep-datta
Copy link

I was told to leave a comment here instead of opening a new issue:
Rename string::push_str to string::concat #20857

Please consider renaming string::push_str() to string::concat(). Push_X() in the context of a collection means X will be added to the container as a single entity. Hence push_str() is meaningless for strings since a string can only contain characters (char != [char]).

If it is too late to rename then consider adding a method called concat() anyway.

Also consider renaming Vec::push_all() to Vec::concat() so that the name is consistent with String::concat().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-collections Proposals about collection APIs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet