RFC: Collections reform #235

Merged
merged 7 commits into from Oct 29, 2014

Conversation

Projects
None yet
@aturon
Member

aturon commented Sep 11, 2014

This is a combined conventions and library stabilization RFC. The goal is to establish a set of naming and signature conventions for std::collections.

The major components of the RFC include:

  • Removing the traits in collections.
  • A general proposal for solving the "equiv" problem, as well as improving MaybeOwned.
  • Patterns for overloading on by-need values and predicates.
  • Initial, forwards-compatible steps toward Iterable.
  • A coherent set of API conventions across the full variety of collections.

A big thank-you to @Gankro, who helped collect API information and worked through an initial pass of some of the proposals here.

Rendered

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Sep 11, 2014

Member

cc #17

Member

aturon commented Sep 11, 2014

cc #17

active/0000-collections-conventions.md
+
+impl<T: Eq> Predicate<T> for &T {
+ fn check(&self, t: &T) -> bool {
+ self == t

This comment has been minimized.

@Gankro

Gankro Sep 11, 2014

Contributor

Pretty sure these need to be dereffed, unless the semantics of operators have changed from underneath me.

@Gankro

Gankro Sep 11, 2014

Contributor

Pretty sure these need to be dereffed, unless the semantics of operators have changed from underneath me.

active/0000-collections-conventions.md
+fn with_capacity(uint) -> Self
+fn capacity(&self) -> uint
+fn reserve(&mut self, uint)
+fn reserve_exact(&mut self, uint)

This comment has been minimized.

@Gankro

Gankro Sep 11, 2014

Contributor

Signatures still missing names for the uints.

@Gankro

Gankro Sep 11, 2014

Contributor

Signatures still missing names for the uints.

active/0000-collections-conventions.md
+
+impl<T> Borrow for [T] {
+ type Owned = Vec<T>;
+ fn borrow(s: &Vec<T>) -> &[T] {

This comment has been minimized.

@andrew-d

andrew-d Sep 11, 2014

typo: s --> self (and also in borrow_mut, below)

@andrew-d

andrew-d Sep 11, 2014

typo: s --> self (and also in borrow_mut, below)

This comment has been minimized.

@Gankro

Gankro Sep 11, 2014

Contributor

It's a static function, not an instance method.

Edit: This is because many structures can implement Borrow for the same type. E.G. &String and &str are both Borrow for String as far as I can tell.

@Gankro

Gankro Sep 11, 2014

Contributor

It's a static function, not an instance method.

Edit: This is because many structures can implement Borrow for the same type. E.G. &String and &str are both Borrow for String as far as I can tell.

This comment has been minimized.

@andrew-d

andrew-d Sep 11, 2014

Ah, fair enough then. That being said: the selfs below should probably be changed to s then 😄

@andrew-d

andrew-d Sep 11, 2014

Ah, fair enough then. That being said: the selfs below should probably be changed to s then 😄

This comment has been minimized.

@aturon

aturon Sep 11, 2014

Member

@andrew-d Thanks, fixed!

@aturon

aturon Sep 11, 2014

Member

@andrew-d Thanks, fixed!

This comment has been minimized.

@P1start

P1start Oct 5, 2014

Contributor

Now that borrow is an instance method, s should probably be changed to self.

@P1start

P1start Oct 5, 2014

Contributor

Now that borrow is an instance method, s should probably be changed to self.

active/0000-collections-conventions.md
+fn iter_from(&self, k: &K) -> Entries<'a, K, V>
+fn iter_from_mut(&mut self, k: &K) -> EntriesMut<'a, K, V>
+
+Returns an iterator starting with the first key-value pair whose key is greater than k.

This comment has been minimized.

@Gankro

Gankro Sep 11, 2014

Contributor

//

@Gankro

Gankro Sep 11, 2014

Contributor

//

active/0000-collections-conventions.md
+
+```rust
+fn keys(&'a self) -> Keys<'a, K>
+fn values(&'a self) -> Values<'a, V>

This comment has been minimized.

@Gankro

Gankro Sep 11, 2014

Contributor

mut_values is certainly possible, but probably pushing it.

@Gankro

Gankro Sep 11, 2014

Contributor

mut_values is certainly possible, but probably pushing it.

active/0000-collections-conventions.md
+for x in &v { ... } // iterate over &Foo
+for x in &mut v { ... } // iterate over &mut Foo
+for x in v { ... } // iterate over Foo
+```

This comment has been minimized.

@alexcrichton

alexcrichton Sep 11, 2014

Member

This would also yield patterns like:

for x in v { ... } // iterate over Foo
for x in v.iter() { ... } // iterate over &Foo

These both seem quite ergonomic and quite tempting, and look fairly similar, yet yield different results. I'd be ok with it, does it sound ok to you?

@alexcrichton

alexcrichton Sep 11, 2014

Member

This would also yield patterns like:

for x in v { ... } // iterate over Foo
for x in v.iter() { ... } // iterate over &Foo

These both seem quite ergonomic and quite tempting, and look fairly similar, yet yield different results. I'd be ok with it, does it sound ok to you?

This comment has been minimized.

@Gankro

Gankro Sep 11, 2014

Contributor

It's probably unlikely that you wouldn't notice very quickly if you used the wrong one. Although I could see this burning newbies.

@Gankro

Gankro Sep 11, 2014

Contributor

It's probably unlikely that you wouldn't notice very quickly if you used the wrong one. Although I could see this burning newbies.

This comment has been minimized.

@aturon

aturon Sep 11, 2014

Member

@alexcrichton Yes, the fact that the "default" interpretation is a moving iterator is perhaps a bit weird. On the other hand, moving is the default almost everywhere in Rust, and with this approach you get to use & and &mut to easily select other forms of iteration.

Unfortunately, it's a bit tricky to make for use by-ref iterators instead. The problem is that an iterator is IntoIterator, but it is not Iterable (or whatever we call the by-reference trait). Why? Because IntoIterator gives you an iterator that can be used only once, while Iterable allows you to ask for iterators repeatedly.

If for demanded an Iterable, then for x in v.iter() and for x in v.iter_mut() would cease to work -- we'd have to find some other approach. It might be doable, but offhand I don't see how.

@aturon

aturon Sep 11, 2014

Member

@alexcrichton Yes, the fact that the "default" interpretation is a moving iterator is perhaps a bit weird. On the other hand, moving is the default almost everywhere in Rust, and with this approach you get to use & and &mut to easily select other forms of iteration.

Unfortunately, it's a bit tricky to make for use by-ref iterators instead. The problem is that an iterator is IntoIterator, but it is not Iterable (or whatever we call the by-reference trait). Why? Because IntoIterator gives you an iterator that can be used only once, while Iterable allows you to ask for iterators repeatedly.

If for demanded an Iterable, then for x in v.iter() and for x in v.iter_mut() would cease to work -- we'd have to find some other approach. It might be doable, but offhand I don't see how.

This comment has been minimized.

@aturon

aturon Sep 11, 2014

Member

(I've added this text to the RFC)

@aturon

aturon Sep 11, 2014

Member

(I've added this text to the RFC)

This comment has been minimized.

@zkamsler

zkamsler Sep 12, 2014

Making for use IntoIterator exclusively would prevent one from using an Iterator after partially iterating over it with a for. This is possible now, since it is mutably borrowed. Ideally, for would treat an Iterator differently from a non-iterator, but then it would have to be more than a parser desugaring.

@zkamsler

zkamsler Sep 12, 2014

Making for use IntoIterator exclusively would prevent one from using an Iterator after partially iterating over it with a for. This is possible now, since it is mutably borrowed. Ideally, for would treat an Iterator differently from a non-iterator, but then it would have to be more than a parser desugaring.

This comment has been minimized.

@thestinger

thestinger Sep 16, 2014

I don't think moving out of a container should be the default iterator. I'm strongly against adding an Iterable trait until there's a proposal without it. Containers shouldn't be treated as cheap temporaries. Moving from a container via an iterator is far from being the common case. It's such an edge case that more sugar for it is totally unnecessary and will lead people down the wrong path.

@thestinger

thestinger Sep 16, 2014

I don't think moving out of a container should be the default iterator. I'm strongly against adding an Iterable trait until there's a proposal without it. Containers shouldn't be treated as cheap temporaries. Moving from a container via an iterator is far from being the common case. It's such an edge case that more sugar for it is totally unnecessary and will lead people down the wrong path.

This comment has been minimized.

@pcwalton

pcwalton Sep 16, 2014

Contributor

I don't see how moving out encourages people to treat containers to be cheap temporaries. You still have to create the container in the first place, via .collect() or Vec::new() or whatnot.

@pcwalton

pcwalton Sep 16, 2014

Contributor

I don't see how moving out encourages people to treat containers to be cheap temporaries. You still have to create the container in the first place, via .collect() or Vec::new() or whatnot.

This comment has been minimized.

@huonw

huonw Sep 17, 2014

Member

It renders the container unusable later, so people will apply the clone hammer; e.g. with a scenario like

let v: Vec<int> = ...;
let mut result = 0;
for x in v {
    result += f(x);
}

return (result, v);

I'm 100% sure that there will be people who fix the compiler error with for x in v.clone() (and I would guess that it won't be a trivial number). I also have a feeling that consuming iteration is likely to be the least efficient in general:

  • large values will be (in general) unoptimisably memcpy'd around
  • when iterating over something complicated like treemap, consuming it will probably have to be quite careful to avoid crashes; possibly at the expense of speed
@huonw

huonw Sep 17, 2014

Member

It renders the container unusable later, so people will apply the clone hammer; e.g. with a scenario like

let v: Vec<int> = ...;
let mut result = 0;
for x in v {
    result += f(x);
}

return (result, v);

I'm 100% sure that there will be people who fix the compiler error with for x in v.clone() (and I would guess that it won't be a trivial number). I also have a feeling that consuming iteration is likely to be the least efficient in general:

  • large values will be (in general) unoptimisably memcpy'd around
  • when iterating over something complicated like treemap, consuming it will probably have to be quite careful to avoid crashes; possibly at the expense of speed

This comment has been minimized.

@aturon

aturon Sep 17, 2014

Member

A couple of points here:

  1. I don't see any simple way to make for use an Iterable-style API that defaults to by-reference, for reasons that I outlined here. Basically, an iterator can only implement a by-value Iterable API.

    Please let me know if you see a way around this, though.

  2. In terms of shaping what people do, note that the ergonomics of for x in v and for x in &v are almost identical. So I think the main thing is documentation. When we first introduce iteration in the docs, we would surely show for x in &v and explain what the & is doing. If we make sure that programmers are made aware of that from their first encounter with iteration, I think it's unlikely that they'd reach for .clone.

  3. Moving is the default almost everywhere in Rust. To me, writing for x in &v serves as a nice signal to the reader that references are being taken. It also plays quite nicely with the deref coercions that I've recently proposed.

@aturon

aturon Sep 17, 2014

Member

A couple of points here:

  1. I don't see any simple way to make for use an Iterable-style API that defaults to by-reference, for reasons that I outlined here. Basically, an iterator can only implement a by-value Iterable API.

    Please let me know if you see a way around this, though.

  2. In terms of shaping what people do, note that the ergonomics of for x in v and for x in &v are almost identical. So I think the main thing is documentation. When we first introduce iteration in the docs, we would surely show for x in &v and explain what the & is doing. If we make sure that programmers are made aware of that from their first encounter with iteration, I think it's unlikely that they'd reach for .clone.

  3. Moving is the default almost everywhere in Rust. To me, writing for x in &v serves as a nice signal to the reader that references are being taken. It also plays quite nicely with the deref coercions that I've recently proposed.

This comment has been minimized.

@huonw

huonw Sep 17, 2014

Member

I do agree that it's hard to do a by ref iterator with a naive Iterable API.

There are some points in the other direction:

  • I believe unconditionally calling IntoIterator (i.e. not dectecting and handling Iterators specially) will stop rust-lang/rust#8372 being possible, since the iterator for ... in iter { ... } wlll be moved (or duplicated) and thus either iter will not be usable in the body, or it will not refer to the same thing as the for loop head.

  • Some containers can only provide &, i.e. & is the lowest common denominator.

  • On that note, it is weird that for x in v is by value for Vec but by reference for &[], assuming this is the case, anyway (and there's a similar difference for for x in map e.g. if map is a function argument that is passed as &HashMap<...> vs. if it is a local).

  • If we make sure that programmers are made aware of that from their first encounter with iteration, I think it's unlikely that they'd reach for .clone.

    Well, people do a lot of passing Vec and String by value now, even when they could just pass & if not &str or &[]; maybe that's just a problem with our documentation.

@huonw

huonw Sep 17, 2014

Member

I do agree that it's hard to do a by ref iterator with a naive Iterable API.

There are some points in the other direction:

  • I believe unconditionally calling IntoIterator (i.e. not dectecting and handling Iterators specially) will stop rust-lang/rust#8372 being possible, since the iterator for ... in iter { ... } wlll be moved (or duplicated) and thus either iter will not be usable in the body, or it will not refer to the same thing as the for loop head.

  • Some containers can only provide &, i.e. & is the lowest common denominator.

  • On that note, it is weird that for x in v is by value for Vec but by reference for &[], assuming this is the case, anyway (and there's a similar difference for for x in map e.g. if map is a function argument that is passed as &HashMap<...> vs. if it is a local).

  • If we make sure that programmers are made aware of that from their first encounter with iteration, I think it's unlikely that they'd reach for .clone.

    Well, people do a lot of passing Vec and String by value now, even when they could just pass & if not &str or &[]; maybe that's just a problem with our documentation.

active/0000-collections-conventions.md
+ fn cloned(self) -> Option<T> {
+ self.map(|x| x.clone())
+ }
+ ```

This comment has been minimized.

@alexcrichton

alexcrichton Sep 11, 2014

Member

Could this actually take T: Borrow to convert Option<&str> to Option<String>?

@alexcrichton

alexcrichton Sep 11, 2014

Member

Could this actually take T: Borrow to convert Option<&str> to Option<String>?

This comment has been minimized.

@aturon

aturon Sep 11, 2014

Member

It could indeed! (Well, it'd take T: ToOwned).

And perhaps, more generally, we may find that a ToOwned bound is more useful than a Clone bound in many cases, for exactly this reason.

@aturon

aturon Sep 11, 2014

Member

It could indeed! (Well, it'd take T: ToOwned).

And perhaps, more generally, we may find that a ToOwned bound is more useful than a Clone bound in many cases, for exactly this reason.

active/0000-collections-conventions.md
+`fn get_mut(&mut self, uint) -> Option<&mut T>` | `[T]`, `Vec`, `RingBuf`
+`fn get(&self, &K) -> Option<&V>` | `HashMap`, `TreeMap`, `TrieMap`, `SmallIntMap`
+`fn get_mut(&mut self, &K) -> Option<&mut V>` | `HashMap`, `TreeMap`, `TrieMap`, `SmallIntMap`
+`fn contains<P>(&self, P) where P: Predicate<T>` | `[T]`, `str`, `Vec`, `String`, `DList`, `RingBuf`, `BinaryHeap`

This comment has been minimized.

@alexcrichton

alexcrichton Sep 11, 2014

Member

For strings, if T is char, would it be possible to leverage this method to test if a string contains a substring?

@alexcrichton

alexcrichton Sep 11, 2014

Member

For strings, if T is char, would it be possible to leverage this method to test if a string contains a substring?

This comment has been minimized.

@aturon

aturon Sep 11, 2014

Member

No; we'll need a separate contains_str variant.

@aturon

aturon Sep 11, 2014

Member

No; we'll need a separate contains_str variant.

This comment has been minimized.

@aturon

aturon Sep 11, 2014

Member

Alternatively, we could use a double-dispatch trick to have the String contains method be more general than the interface given here. That's probably fine, and we can make the final decision as part of String stabilization.

@aturon

aturon Sep 11, 2014

Member

Alternatively, we could use a double-dispatch trick to have the String contains method be more general than the interface given here. That's probably fine, and we can make the final decision as part of String stabilization.

@Gankro

This comment has been minimized.

Show comment
Hide comment
@Gankro

Gankro Sep 11, 2014

Contributor

I skimmed/skipped the first 1000 lines assuming it hasn't changed much since last I saw it. Overall I'm a big 👍 to this proposal's contents. Some misc notes that I don't think you ever discussed/addressed:

  • Predicate as written might be better served as a special case of Comparators (on hold pending full unboxed closures). As it stands, it strikes me as odd that equality is "the" element predicate. In particular a function like lower_bound wouldn't be able to use this kind of predicate. This could be more flexible if what we requested was effectively a "partially applied comparator". Or perhaps we can just have a family of traits EqPred, LePred, GePred, etc?
  • Maps love only yielding V from queries in our current design. Would it be possible to yield (K, V) for more map methods? To my knowledge, when you insert a key-value pair, the key always also gets swapped. Some people might want that Key back? With tuple indexing this should be a trivial ergonomic loss. It also means Sets (which are trivial wrappers around maps) can start telling you about their contents beyond "yeah, I got that" or "Okay, I removed something".
Contributor

Gankro commented Sep 11, 2014

I skimmed/skipped the first 1000 lines assuming it hasn't changed much since last I saw it. Overall I'm a big 👍 to this proposal's contents. Some misc notes that I don't think you ever discussed/addressed:

  • Predicate as written might be better served as a special case of Comparators (on hold pending full unboxed closures). As it stands, it strikes me as odd that equality is "the" element predicate. In particular a function like lower_bound wouldn't be able to use this kind of predicate. This could be more flexible if what we requested was effectively a "partially applied comparator". Or perhaps we can just have a family of traits EqPred, LePred, GePred, etc?
  • Maps love only yielding V from queries in our current design. Would it be possible to yield (K, V) for more map methods? To my knowledge, when you insert a key-value pair, the key always also gets swapped. Some people might want that Key back? With tuple indexing this should be a trivial ergonomic loss. It also means Sets (which are trivial wrappers around maps) can start telling you about their contents beyond "yeah, I got that" or "Okay, I removed something".
@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Sep 11, 2014

Member

@Gankro I addressed the various typos you pointed out.

Predicate as written might be better served as a special case of Comparators (on hold pending full unboxed closures). As it stands, it strikes me as odd that equality is "the" element predicate. In particular a function like lower_bound wouldn't be able to use this kind of predicate. This could be more flexible if what we requested was effectively a "partially applied comparator". Or perhaps we can just have a family of traits EqPred, LePred, GePred, etc?

I don't think methods like lower_bound make sense to take a more general closure, since they rely intrinsically on ordering. I think that's true more generally: if you have a method that can take an arbitrary predicate on a type, it's unlikely that the natural way to interpret an element of that type is via some ordering.

That said, we could consider using PredEq or some such name, to leave room for adding other predicates with different defaults in the future if they turn out to be wanted.

Maps love only yielding V from queries in our current design. Would it be possible to yield (K, V) for more map methods? To my knowledge, when you insert a key-value pair, the key always also gets swapped. Some people might want that Key back? With tuple indexing this should be a trivial ergonomic loss. It also means Sets (which are trivial wrappers around maps) can start telling you about their contents beyond "yeah, I got that" or "Okay, I removed something".

That's certainly doable. It's a tradeoff, since it makes the API somewhat more complex for a pretty rare use case.

My plan for key recovery was to go through your collection view's RFC, which offers a bit more of a swiss army knife for working with maps. We'll have to think about sets, though.

Member

aturon commented Sep 11, 2014

@Gankro I addressed the various typos you pointed out.

Predicate as written might be better served as a special case of Comparators (on hold pending full unboxed closures). As it stands, it strikes me as odd that equality is "the" element predicate. In particular a function like lower_bound wouldn't be able to use this kind of predicate. This could be more flexible if what we requested was effectively a "partially applied comparator". Or perhaps we can just have a family of traits EqPred, LePred, GePred, etc?

I don't think methods like lower_bound make sense to take a more general closure, since they rely intrinsically on ordering. I think that's true more generally: if you have a method that can take an arbitrary predicate on a type, it's unlikely that the natural way to interpret an element of that type is via some ordering.

That said, we could consider using PredEq or some such name, to leave room for adding other predicates with different defaults in the future if they turn out to be wanted.

Maps love only yielding V from queries in our current design. Would it be possible to yield (K, V) for more map methods? To my knowledge, when you insert a key-value pair, the key always also gets swapped. Some people might want that Key back? With tuple indexing this should be a trivial ergonomic loss. It also means Sets (which are trivial wrappers around maps) can start telling you about their contents beyond "yeah, I got that" or "Okay, I removed something".

That's certainly doable. It's a tradeoff, since it makes the API somewhat more complex for a pretty rare use case.

My plan for key recovery was to go through your collection view's RFC, which offers a bit more of a swiss army knife for working with maps. We'll have to think about sets, though.

@epdtry

This comment has been minimized.

Show comment
Hide comment
@epdtry

epdtry Sep 11, 2014

It seems to me that it would be more flexible to define Borrow with both type parameters being "inputs", instead of one input and one output. For example:

trait Borrow<Sized? B> {
    fn borrow(&self) -> &B;
}

impl<T: Sized> Borrow<T> for T { ... }
impl Borrow<str> for String { ... }
impl<T> Borrow<[T]> for Vec<T> { ... }

(I'm not 100% clear about the rules for blanket impls post-trait reform, but the one above seems like it ought to work, based on the blanket Borrow impl that is currently in the RFC.)

Now if you define a custom string type, you can still get the benefits of Borrow without needing to define your own wrapper around str:

struct MyString(String);
impl Borrow<str> for MyString { ... }

It also would let you have String borrow to more than one type:

impl Borrow<[u8]> for String { ... }

Then HashMap would look like this:

struct HashMap<K, V>;
impl<K, V> HashMap<K, V> {
    fn insert(&mut self, k: K, v: V) { ... }
    fn find<B>(&self, k: &B) -> Option<&V> where K: Borrow<B> { ... }
}

And you can still define Cow, though it's not as pretty since you need to specify both the owned and borrowed types:

trait FromBorrow<Sized? B>: Borrow<B> {
    fn from_borrow(b: &B) -> Self;
}

enum Cow<'a, T, B: 'a> where T: FromBorrow<B> {
    Owned(T),
    Shared(&'a B),
}

type MaybeOwned<'a> = Cow<'a, String, str>;

Did you consider implementing Borrow this way? I see the "borrowed -> owned" version in the main body of the RFC, and a sort of "owned -> borrowed" version in the alternatives, but nothing with both "owned" and "borrowed" as inputs.

epdtry commented Sep 11, 2014

It seems to me that it would be more flexible to define Borrow with both type parameters being "inputs", instead of one input and one output. For example:

trait Borrow<Sized? B> {
    fn borrow(&self) -> &B;
}

impl<T: Sized> Borrow<T> for T { ... }
impl Borrow<str> for String { ... }
impl<T> Borrow<[T]> for Vec<T> { ... }

(I'm not 100% clear about the rules for blanket impls post-trait reform, but the one above seems like it ought to work, based on the blanket Borrow impl that is currently in the RFC.)

Now if you define a custom string type, you can still get the benefits of Borrow without needing to define your own wrapper around str:

struct MyString(String);
impl Borrow<str> for MyString { ... }

It also would let you have String borrow to more than one type:

impl Borrow<[u8]> for String { ... }

Then HashMap would look like this:

struct HashMap<K, V>;
impl<K, V> HashMap<K, V> {
    fn insert(&mut self, k: K, v: V) { ... }
    fn find<B>(&self, k: &B) -> Option<&V> where K: Borrow<B> { ... }
}

And you can still define Cow, though it's not as pretty since you need to specify both the owned and borrowed types:

trait FromBorrow<Sized? B>: Borrow<B> {
    fn from_borrow(b: &B) -> Self;
}

enum Cow<'a, T, B: 'a> where T: FromBorrow<B> {
    Owned(T),
    Shared(&'a B),
}

type MaybeOwned<'a> = Cow<'a, String, str>;

Did you consider implementing Borrow this way? I see the "borrowed -> owned" version in the main body of the RFC, and a sort of "owned -> borrowed" version in the alternatives, but nothing with both "owned" and "borrowed" as inputs.

@zkamsler

This comment has been minimized.

Show comment
Hide comment
@zkamsler

zkamsler Sep 12, 2014

I want to like the idea of Borrow, but it can be limiting. It precludes the use of equiv-like keys for HashMap<MyCoolString, int> and the like. String and Vec<T> are not the only things that could be 'borrowed' to str and [T]. They are good defaults, but it feels strange to bless them to the exclusion of everything else.

I want to like the idea of Borrow, but it can be limiting. It precludes the use of equiv-like keys for HashMap<MyCoolString, int> and the like. String and Vec<T> are not the only things that could be 'borrowed' to str and [T]. They are good defaults, but it feels strange to bless them to the exclusion of everything else.

@Gankro

This comment has been minimized.

Show comment
Hide comment
@Gankro

Gankro Sep 12, 2014

Contributor

Hmm, this just occurred to me. The proposal states we would "deprecate" the traits. Is this intended literally (as in #[deprecated]), or will they just be removed overnight? Due to naming conflicts I'm pretty sure that the traits can't coexist in a deprecated form with the proposed concrete impls.

Or will we have a brief period where the traits are deprecated as a warning, with no (merged) replacement?

Contributor

Gankro commented Sep 12, 2014

Hmm, this just occurred to me. The proposal states we would "deprecate" the traits. Is this intended literally (as in #[deprecated]), or will they just be removed overnight? Due to naming conflicts I'm pretty sure that the traits can't coexist in a deprecated form with the proposed concrete impls.

Or will we have a brief period where the traits are deprecated as a warning, with no (merged) replacement?

@sfackler

This comment has been minimized.

Show comment
Hide comment
@sfackler

sfackler Sep 12, 2014

Member

@Gankro:

This RFC proposes a somewhat radical step for the collections traits: rather than reform them, we should eliminate them altogether -- for now.

Member

sfackler commented Sep 12, 2014

@Gankro:

This RFC proposes a somewhat radical step for the collections traits: rather than reform them, we should eliminate them altogether -- for now.

@Gankro

This comment has been minimized.

Show comment
Hide comment
@Gankro

Gankro Sep 12, 2014

Contributor

@sfackler I assumed that wording was simply referring to the standard deprecation -> removal path. I was (am?) uncertain about the nature of the transition.

Contributor

Gankro commented Sep 12, 2014

@sfackler I assumed that wording was simply referring to the standard deprecation -> removal path. I was (am?) uncertain about the nature of the transition.

@reem

This comment has been minimized.

Show comment
Hide comment
@reem

reem Sep 13, 2014

I might just be being dense, but is there a reason for the name Cow?

reem commented Sep 13, 2014

I might just be being dense, but is there a reason for the name Cow?

@sfackler

This comment has been minimized.

Show comment
Hide comment
@sfackler

sfackler Sep 13, 2014

Member

Copy on write I'd assume.

Member

sfackler commented Sep 13, 2014

Copy on write I'd assume.

@Gankro

This comment has been minimized.

Show comment
Hide comment
@Gankro

Gankro Sep 14, 2014

Contributor

One thing I keep remembering and forgetting, and don't really know where to put it, so I'm just going to put here since it's relevant to this work:

Instead of all this lower_bound and upper_bound nonsense, we could probably just provide one method on sorted collections:

/// Creates an iterator over a sub-range of the collection's items, 
/// starting at min, and ending at max. If min is `None`, then it will
/// be treated as "negative infinity", and if max is `None`, then it will
/// be treated as "positive infinity". Thus range(None, None) will yield
/// the whole collection.
fn range(&self, min: Option<&T>, max: Option<&T>) -> SubItems<'a, T>;

This iterator should be DoubleEnded and therefore reversible. This of course doesn't address the inclusive/exclusive scenario, for which we can either do the same thing as range and include an inclusive/exclusive variant, or we can change the Option to a Tristate enum:

Bound<T> {
    Included(T),
    Excluded(T),
    Unbounded,
}

which is the solution I prefer.

Contributor

Gankro commented Sep 14, 2014

One thing I keep remembering and forgetting, and don't really know where to put it, so I'm just going to put here since it's relevant to this work:

Instead of all this lower_bound and upper_bound nonsense, we could probably just provide one method on sorted collections:

/// Creates an iterator over a sub-range of the collection's items, 
/// starting at min, and ending at max. If min is `None`, then it will
/// be treated as "negative infinity", and if max is `None`, then it will
/// be treated as "positive infinity". Thus range(None, None) will yield
/// the whole collection.
fn range(&self, min: Option<&T>, max: Option<&T>) -> SubItems<'a, T>;

This iterator should be DoubleEnded and therefore reversible. This of course doesn't address the inclusive/exclusive scenario, for which we can either do the same thing as range and include an inclusive/exclusive variant, or we can change the Option to a Tristate enum:

Bound<T> {
    Included(T),
    Excluded(T),
    Unbounded,
}

which is the solution I prefer.

@alexcrichton alexcrichton referenced this pull request in rust-lang/rust Sep 16, 2014

Closed

Feature request: Drop the iter() from vec. #17301

active/0000-collections-conventions.md
+methods would go through a reference iterator (i.e. the `iter` method) rather
+than a moving iterator.
+
+It is possible to add such methods using the design proposed above, but there

This comment has been minimized.

@thestinger

thestinger Sep 16, 2014

It shouldn't produce a vector. Creating containers is very expensive and lazy iterators should be encouraged. An API producing temporary container will result in countless accidentally temporaries, as demonstrated by the code conventions in the compiler.

@thestinger

thestinger Sep 16, 2014

It shouldn't produce a vector. Creating containers is very expensive and lazy iterators should be encouraged. An API producing temporary container will result in countless accidentally temporaries, as demonstrated by the code conventions in the compiler.

active/0000-collections-conventions.md
+with these iterators avoids materializing intermediate sets when they're not
+needed; the `collect` method can be used to create sets when they are.
+
+To clarify the API, this RFC proposes renaming the methods to `iter_or`,

This comment has been minimized.

@thestinger

thestinger Sep 16, 2014

I don't think this would do a good job conveying that these are the basic set operations to most people. Unless looking up union in the documentation will find iter_or... I don't think it will today.

@thestinger

thestinger Sep 16, 2014

I don't think this would do a good job conveying that these are the basic set operations to most people. Unless looking up union in the documentation will find iter_or... I don't think it will today.

This comment has been minimized.

@aturon

aturon Sep 17, 2014

Member

That's a fair point. But one problem is that there are really several versions of the "basic set operations": those returning iterators, those returning new sets, and those mutating self. I'd love to hear any proposal for a naming convention that covers all of these cases more clearly.

@aturon

aturon Sep 17, 2014

Member

That's a fair point. But one problem is that there are really several versions of the "basic set operations": those returning iterators, those returning new sets, and those mutating self. I'd love to hear any proposal for a naming convention that covers all of these cases more clearly.

@aturon aturon referenced this pull request Sep 16, 2014

Merged

Collection Views #216

active/0000-collections-conventions.md
+
+* It doesn't help with the `MaybeOwned` problem.
+
+* It exposes some representation interplay between slices and references to

This comment has been minimized.

@thestinger

thestinger Sep 16, 2014

It's correct and is going to have to remain correct, because these are basic stability guarantees required by unsafe code.

@thestinger

thestinger Sep 16, 2014

It's correct and is going to have to remain correct, because these are basic stability guarantees required by unsafe code.

active/0000-collections-conventions.md
+@strcat has a [PR](https://github.com/rust-lang/rust/pull/16713) that makes it
+possible to, for example, coerce a `&str` to an `&String` value.
+
+This provides some help for the `_equiv` problem, since the `_equiv` methods

This comment has been minimized.

@thestinger

thestinger Sep 16, 2014

It's one of the things it helps with, but it's more broadly applicable.

@thestinger

thestinger Sep 16, 2014

It's one of the things it helps with, but it's more broadly applicable.

active/0000-collections-conventions.md
+
+### Handling of `for` loops
+
+The fact that `for x in v` moves elements from `v`, while `for x in v.iter()`

This comment has been minimized.

@thestinger

thestinger Sep 16, 2014

I think moving out of containers by default encourages a poor coding style. Containers should be treated as very expensive objects and reused whenever possible. The sugary coding style shouldn't be the one where containers are created and torn down as temporaries.

@thestinger

thestinger Sep 16, 2014

I think moving out of containers by default encourages a poor coding style. Containers should be treated as very expensive objects and reused whenever possible. The sugary coding style shouldn't be the one where containers are created and torn down as temporaries.

active/0000-collections-conventions.md
+v.extend(some_vec);
+```
+
+However, currently the `push_all` and `push_all_move` methods can rely on the

This comment has been minimized.

@thestinger

thestinger Sep 16, 2014

#[experimental] #[inline(always) unsafe fn size_hint_is_correct(&self) -> bool { false } would work today and would be backwards / forwards compatible. It would introduce a lot of unsafety to the iterator module though. Each adaptor with a size hint would need to assert that the size_hint and next methods are implemented correctly. At this rate, nearly the entire standard library is going to end up unsafe... and this applies to any third party iterators too.

@thestinger

thestinger Sep 16, 2014

#[experimental] #[inline(always) unsafe fn size_hint_is_correct(&self) -> bool { false } would work today and would be backwards / forwards compatible. It would introduce a lot of unsafety to the iterator module though. Each adaptor with a size hint would need to assert that the size_hint and next methods are implemented correctly. At this rate, nearly the entire standard library is going to end up unsafe... and this applies to any third party iterators too.

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Sep 17, 2014

Member

@epdtry Thanks for the suggestion -- I hadn't thought of that particular variant. I think it's more intuitive, but it does have a few downsides. First, the Cow complication that you pointed out. Second, the fact that there's no longer any guarantee about "coherence" for hashing/ordering, since you can pass in different borrow types at different times (and these could hash differently).

Neither of those are necessarily deal-breakers, though. I'll add this alternative to the RFC, and think more about which I prefer. I'd also be interested to hear feedback/preferences from others.

@zkamsler, I believe @epdtry's version of Borrow would address your worry as well.

Member

aturon commented Sep 17, 2014

@epdtry Thanks for the suggestion -- I hadn't thought of that particular variant. I think it's more intuitive, but it does have a few downsides. First, the Cow complication that you pointed out. Second, the fact that there's no longer any guarantee about "coherence" for hashing/ordering, since you can pass in different borrow types at different times (and these could hash differently).

Neither of those are necessarily deal-breakers, though. I'll add this alternative to the RFC, and think more about which I prefer. I'd also be interested to hear feedback/preferences from others.

@zkamsler, I believe @epdtry's version of Borrow would address your worry as well.

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Sep 17, 2014

Member

@Gankro I really like the range idea; I'm going to update the RFC with it.

Member

aturon commented Sep 17, 2014

@Gankro I really like the range idea; I'm going to update the RFC with it.

@Gankro

This comment has been minimized.

Show comment
Hide comment
@Gankro

Gankro Sep 17, 2014

Contributor

I'm on the fence about @epdtry's proposal. I like that you can provide whatever is the most convenient "borrow" of the item at any given time. It also makes the signature of Maps sane again. It's a Map<K, V>, that's what it should be, ideally. I also think that anything other than Map<K, V> will make it harder to infer collections in the small, too. Just inserting elements into it isn't sufficient. Although this is probably a strange corner case.

However guaranteed/idiot-proof hashing/ordering is tempting.

Does anyone have a concrete/real usecase where they really want to be able to search with multiple "equiv" items on the same map?

Regardless, I don't think the actual Borrow/ToOwned types need to change to achieve this. Although I don't have a full mental picture of Where Clauses, AI, Trait Reform, etc. so maybe this doesn't work:

     fn find<B: Borrow>(&self, k: &B) -> Option<&V> where B::Owned = K { ... }
Contributor

Gankro commented Sep 17, 2014

I'm on the fence about @epdtry's proposal. I like that you can provide whatever is the most convenient "borrow" of the item at any given time. It also makes the signature of Maps sane again. It's a Map<K, V>, that's what it should be, ideally. I also think that anything other than Map<K, V> will make it harder to infer collections in the small, too. Just inserting elements into it isn't sufficient. Although this is probably a strange corner case.

However guaranteed/idiot-proof hashing/ordering is tempting.

Does anyone have a concrete/real usecase where they really want to be able to search with multiple "equiv" items on the same map?

Regardless, I don't think the actual Borrow/ToOwned types need to change to achieve this. Although I don't have a full mental picture of Where Clauses, AI, Trait Reform, etc. so maybe this doesn't work:

     fn find<B: Borrow>(&self, k: &B) -> Option<&V> where B::Owned = K { ... }
@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Sep 17, 2014

Member

@Gankro Can you elaborate on the following:

It also makes the signature of Maps sane again. It's a Map, that's what it should be, ideally. I also think that anything other than Map will make it harder to infer collections in the small, too. Just inserting elements into it isn't sufficient.

Do you mean HashMap<String, T> rather than HashMap<str, T> as being a "sane" signature, or something else? (I do agree that taking the owned key as the argument is more intuitive). Also, I don't understand the point about inference.

But actually, I now see a problem with @epdtry's proposal as well as your alternative signature

fn find<B: Borrow>(&self, k: &B) -> Option<&V> where B::Owned = K { ... }

In particular, you need to know that you can compare an &B and a &B::Owned for equality -- basically, putting us full circle back to Equiv.

Member

aturon commented Sep 17, 2014

@Gankro Can you elaborate on the following:

It also makes the signature of Maps sane again. It's a Map, that's what it should be, ideally. I also think that anything other than Map will make it harder to infer collections in the small, too. Just inserting elements into it isn't sufficient.

Do you mean HashMap<String, T> rather than HashMap<str, T> as being a "sane" signature, or something else? (I do agree that taking the owned key as the argument is more intuitive). Also, I don't understand the point about inference.

But actually, I now see a problem with @epdtry's proposal as well as your alternative signature

fn find<B: Borrow>(&self, k: &B) -> Option<&V> where B::Owned = K { ... }

In particular, you need to know that you can compare an &B and a &B::Owned for equality -- basically, putting us full circle back to Equiv.

@epdtry

This comment has been minimized.

Show comment
Hide comment
@epdtry

epdtry Sep 17, 2014

@aturon

In particular, you need to know that you can compare an &B and a &B::Owned for equality -- basically, putting us full circle back to Equiv.

As long as B: Eq, you can borrow the key to get a &B, and to the comparison on that.

epdtry commented Sep 17, 2014

@aturon

In particular, you need to know that you can compare an &B and a &B::Owned for equality -- basically, putting us full circle back to Equiv.

As long as B: Eq, you can borrow the key to get a &B, and to the comparison on that.

@Gankro

This comment has been minimized.

Show comment
Hide comment
@Gankro

Gankro Sep 17, 2014

Contributor

@aturon Ah, sorry, github ate some accidental HTML there. Fixed.

Would it be possible to have something like Map<K, V, B=&K>? That way in normal usage you just use a HashMap<K,V>, and if you need the extra expressiveness, you can override the third parameter?

Contributor

Gankro commented Sep 17, 2014

@aturon Ah, sorry, github ate some accidental HTML there. Fixed.

Would it be possible to have something like Map<K, V, B=&K>? That way in normal usage you just use a HashMap<K,V>, and if you need the extra expressiveness, you can override the third parameter?

@Gankro

This comment has been minimized.

Show comment
Hide comment
@Gankro

Gankro Oct 9, 2014

Contributor

The summary says "removing most of the traits in collections" but the main body seems to otherwise suggest removing them all. Could you clarify?

Contributor

Gankro commented Oct 9, 2014

The summary says "removing most of the traits in collections" but the main body seems to otherwise suggest removing them all. Could you clarify?

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Oct 9, 2014

Member

@Gankro they'll all be nuked.

Member

aturon commented Oct 9, 2014

@Gankro they'll all be nuked.

active/0000-collections-conventions.md
+trait Iter {
+ type A;
+ type I<'a>: Iterator<&'a A>;
+ fn iter<'a>(&self) -> I<'a>;

This comment has been minimized.

@jgallagher

jgallagher Oct 10, 2014

Should this be &'a self?

@jgallagher

jgallagher Oct 10, 2014

Should this be &'a self?

@CloudiDust

This comment has been minimized.

Show comment
Hide comment
@CloudiDust

CloudiDust Oct 12, 2014

Contributor

@aturon, oh, I forgot multidispatch and assumed that each type could have only one Borrow impl at most.

So we can have multiple "borrow strategies" for each type, one of which guaranteed to be "simple address taking".

And now I believe another name for Borrow is not needed. :)

Contributor

CloudiDust commented Oct 12, 2014

@aturon, oh, I forgot multidispatch and assumed that each type could have only one Borrow impl at most.

So we can have multiple "borrow strategies" for each type, one of which guaranteed to be "simple address taking".

And now I believe another name for Borrow is not needed. :)

@japaric japaric referenced this pull request in rust-lang/rust Oct 13, 2014

Closed

add Iterable traits #7597

@aturon aturon referenced this pull request in rust-lang/rust Oct 15, 2014

Closed

remove the into_vec method from &[T] #17916

@Gankro Gankro referenced this pull request in rust-lang/rust Oct 21, 2014

Closed

`DList` should have a method to split the list up #18202

@alexcrichton alexcrichton referenced this pull request in rust-lang/rust Oct 24, 2014

Closed

Rename to as str #17171

@alexcrichton alexcrichton merged commit 3825c86 into rust-lang:master Oct 29, 2014

@alexcrichton

This comment has been minimized.

Show comment
Hide comment
@alexcrichton

alexcrichton Oct 29, 2014

Member

Discussion

Tracking issue coming soon, gonna fill it out a bit first

Member

alexcrichton commented Oct 29, 2014

Discussion

Tracking issue coming soon, gonna fill it out a bit first

@alexcrichton alexcrichton referenced this pull request in rust-lang/rust Oct 29, 2014

Closed

Implement collections reform #18424

23 of 24 tasks complete
@alexcrichton

This comment has been minimized.

Show comment
Hide comment

aturon added a commit to aturon/rust that referenced this pull request Nov 13, 2014

libcore: add borrow module
Following [the collections reform
RFC](rust-lang/rfcs#235),
this commit adds a new `borrow` module to libcore.

The module contains traits for borrowing data (`BorrowFrom` and
`BorrowFromMut`),
generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

aturon added a commit to aturon/rust that referenced this pull request Nov 13, 2014

libcore: add borrow module
Following [the collections reform
RFC](rust-lang/rfcs#235),
this commit adds a new `borrow` module to libcore.

The module contains traits for borrowing data (`BorrowFrom` and
`BorrowFromMut`),
generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

aturon added a commit to aturon/rust that referenced this pull request Nov 14, 2014

libcore: add borrow module
Following [the collections reform
RFC](rust-lang/rfcs#235),
this commit adds a new `borrow` module to libcore.

The module contains traits for borrowing data (`BorrowFrom` and
`BorrowFromMut`),
generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

aturon added a commit to aturon/rust that referenced this pull request Nov 14, 2014

libcore: add borrow module
Following [the collections reform
RFC](rust-lang/rfcs#235),
this commit adds a new `borrow` module to libcore.

The module contains traits for borrowing data (`BorrowFrom` and
`BorrowFromMut`),
generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

bors added a commit to rust-lang/rust that referenced this pull request Nov 16, 2014

auto merge of #18910 : aturon/rust/borrow-traits, r=alexcrichton
Following [the collections reform RFC](rust-lang/rfcs#235), this PR:

* Adds a new `borrow` module to libcore. The module contains traits for borrowing data (`BorrowFrom` and `BorrowFromMut`), generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

* Deprecates the `_equiv` family of methods on `HashMap` and `HashSet` by instead generalizing the "normal" methods like `get` and `remove` to use the new `std::borrow` infrastructure.

* Generalizes `TreeMap`, `TreeSet`, `BTreeMap` and `BTreeSet` to use the new `std::borrow` infrastructure for lookups.

[breaking-change]

aturon added a commit to aturon/rust that referenced this pull request Nov 16, 2014

libcore: add borrow module
Following [the collections reform
RFC](rust-lang/rfcs#235),
this commit adds a new `borrow` module to libcore.

The module contains traits for borrowing data (`BorrowFrom` and
`BorrowFromMut`),
generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

bors added a commit to rust-lang/rust that referenced this pull request Nov 16, 2014

auto merge of #18910 : aturon/rust/borrow-traits, r=alexcrichton
Following [the collections reform RFC](rust-lang/rfcs#235), this PR:

* Adds a new `borrow` module to libcore. The module contains traits for borrowing data (`BorrowFrom` and `BorrowFromMut`), generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

* Deprecates the `_equiv` family of methods on `HashMap` and `HashSet` by instead generalizing the "normal" methods like `get` and `remove` to use the new `std::borrow` infrastructure.

* Generalizes `TreeMap`, `TreeSet`, `BTreeMap` and `BTreeSet` to use the new `std::borrow` infrastructure for lookups.

[breaking-change]

aturon added a commit to aturon/rust that referenced this pull request Nov 16, 2014

libcore: add borrow module
Following [the collections reform
RFC](rust-lang/rfcs#235),
this commit adds a new `borrow` module to libcore.

The module contains traits for borrowing data (`BorrowFrom` and
`BorrowFromMut`),
generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

bors added a commit to rust-lang/rust that referenced this pull request Nov 17, 2014

auto merge of #18910 : aturon/rust/borrow-traits, r=alexcrichton
Following [the collections reform RFC](rust-lang/rfcs#235), this PR:

* Adds a new `borrow` module to libcore. The module contains traits for borrowing data (`BorrowFrom` and `BorrowFromMut`), generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

* Deprecates the `_equiv` family of methods on `HashMap` and `HashSet` by instead generalizing the "normal" methods like `get` and `remove` to use the new `std::borrow` infrastructure.

* Generalizes `TreeMap`, `TreeSet`, `BTreeMap` and `BTreeSet` to use the new `std::borrow` infrastructure for lookups.

[breaking-change]

bors added a commit to rust-lang/rust that referenced this pull request Nov 17, 2014

auto merge of #18910 : aturon/rust/borrow-traits, r=alexcrichton
Following [the collections reform RFC](rust-lang/rfcs#235), this PR:

* Adds a new `borrow` module to libcore. The module contains traits for borrowing data (`BorrowFrom` and `BorrowFromMut`), generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

* Deprecates the `_equiv` family of methods on `HashMap` and `HashSet` by instead generalizing the "normal" methods like `get` and `remove` to use the new `std::borrow` infrastructure.

* Generalizes `TreeMap`, `TreeSet`, `BTreeMap` and `BTreeSet` to use the new `std::borrow` infrastructure for lookups.

[breaking-change]

bors added a commit to rust-lang/rust that referenced this pull request Nov 17, 2014

auto merge of #18910 : aturon/rust/borrow-traits, r=alexcrichton
Following [the collections reform RFC](rust-lang/rfcs#235), this PR:

* Adds a new `borrow` module to libcore. The module contains traits for borrowing data (`BorrowFrom` and `BorrowFromMut`), generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

* Deprecates the `_equiv` family of methods on `HashMap` and `HashSet` by instead generalizing the "normal" methods like `get` and `remove` to use the new `std::borrow` infrastructure.

* Generalizes `TreeMap`, `TreeSet`, `BTreeMap` and `BTreeSet` to use the new `std::borrow` infrastructure for lookups.

[breaking-change]

bors added a commit to rust-lang/rust that referenced this pull request Nov 17, 2014

auto merge of #18910 : aturon/rust/borrow-traits, r=alexcrichton
Following [the collections reform RFC](rust-lang/rfcs#235), this PR:

* Adds a new `borrow` module to libcore. The module contains traits for borrowing data (`BorrowFrom` and `BorrowFromMut`), generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

* Deprecates the `_equiv` family of methods on `HashMap` and `HashSet` by instead generalizing the "normal" methods like `get` and `remove` to use the new `std::borrow` infrastructure.

* Generalizes `TreeMap`, `TreeSet`, `BTreeMap` and `BTreeSet` to use the new `std::borrow` infrastructure for lookups.

[breaking-change]

aturon added a commit to aturon/rust that referenced this pull request Nov 17, 2014

libcore: add borrow module
Following [the collections reform
RFC](rust-lang/rfcs#235),
this commit adds a new `borrow` module to libcore.

The module contains traits for borrowing data (`BorrowFrom` and
`BorrowFromMut`),
generalized cloning (`ToOwned`), and a clone-on-write smartpointer (`Cow`).

@csouth3 csouth3 referenced this pull request in rust-lang/rust Dec 22, 2014

Merged

Implement BitOps for HashSet #20125

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

rollup merge of #20125: csouth3/hashset-bitops
Now that #19448 has landed in a snapshot, we can add proper by-value operator overloads for `HashSet`.  The behavior of these operator overloads is consistent with rust-lang/rfcs#235.

@Stebalien Stebalien referenced this pull request in rust-lang/rust Apr 28, 2015

Merged

Implement retain for VecDeque #24879

bors added a commit to rust-lang/rust that referenced this pull request May 1, 2015

Auto merge of #24879 - Stebalien:vec_deque, r=alexcrichton
According to rust-lang/rfcs#235, `VecDeque` should have this method (`VecDeque` was called `RingBuf` at the time) but it was never implemented.

I marked this stable since "1.0.0" because it's stable in `Vec`.

bors added a commit to rust-lang/rust that referenced this pull request May 5, 2015

Auto merge of #24879 - Stebalien:vec_deque, r=alexcrichton
According to rust-lang/rfcs#235, `VecDeque` should have this method (`VecDeque` was called `RingBuf` at the time) but it was never implemented.

I marked this stable since "1.0.0" because it's stable in `Vec`.

bors added a commit to rust-lang/rust that referenced this pull request May 5, 2015

Auto merge of #24879 - Stebalien:vec_deque, r=alexcrichton
According to rust-lang/rfcs#235, `VecDeque` should have this method (`VecDeque` was called `RingBuf` at the time) but it was never implemented.

I marked this stable since "1.0.0" because it's stable in `Vec`.

bors added a commit to rust-lang/rust that referenced this pull request May 6, 2015

Auto merge of #24879 - Stebalien:vec_deque, r=alexcrichton
According to rust-lang/rfcs#235, `VecDeque` should have this method (`VecDeque` was called `RingBuf` at the time) but it was never implemented.

I marked this stable since "1.0.0" because it's stable in `Vec`.

@SimonSapin SimonSapin referenced this pull request in rust-lang/rust Aug 4, 2015

Closed

Add `ByNeed` and `Predicate` traits #27517

@chriskrycho chriskrycho referenced this pull request in rust-lang/rust Feb 18, 2017

Closed

Document all features in the reference #38643

0 of 17 tasks complete

@chriskrycho chriskrycho referenced this pull request in rust-lang-nursery/reference Mar 11, 2017

Closed

Document all features #9

18 of 48 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment