Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upHave collections impl Extend<&T> where T: copy #839
Conversation
Gankro
changed the title
Upgrade Extend to take IntoIterator<&T> where T: Clone
Upgrade Extend on Collections to take IntoIterator<&T> where T: Clone
Feb 14, 2015
Gankro
changed the title
Upgrade Extend on Collections to take IntoIterator<&T> where T: Clone
Have collections impl Extend for IntoIterator<&T> where T: Clone
Feb 14, 2015
Gankro
changed the title
Have collections impl Extend for IntoIterator<&T> where T: Clone
Have collections impl Extend<&T> where T: Clone
Feb 14, 2015
alexcrichton
reviewed
Feb 16, 2015
| ``` | ||
| /// A type growable from an `Iterator` implementation | ||
| pub trait Extend<T> { | ||
| fn extend<It: Iterator<Item=T>, I: IntoIterator<IntoIter=It>> |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Feb 16, 2015
Member
I'd be fine just dropping this definition entirely from the RFC, I think the definition below should work shortly as well.
This comment has been minimized.
This comment has been minimized.
|
This sounds like a fantastic idea to me, although we would need to move quickly as it is a breaking change to the |
This comment has been minimized.
This comment has been minimized.
|
I believe @aturon always intended everything to work with IntoIterator. Extend not working with it is simply an oversight. Also I don't think it's a backcompat hazard because T: Iterator is IntoIterator. |
This comment has been minimized.
This comment has been minimized.
|
In the trait sense I think it may break code (due to the trait definition changing). For example this is invalid code: trait Foo {
fn foo<I: IntoIterator>(i: I);
}
impl Foo for i32 {
fn foo<I: Iterator>(i: I) { ... }
} |
This comment has been minimized.
This comment has been minimized.
|
Ah yes, of course. Implementors would break. |
This comment has been minimized.
This comment has been minimized.
|
It seems that the |
This comment has been minimized.
This comment has been minimized.
|
Right, the plan was to migrate everything to I'm (obviously) on board with this RFC :-) |
This comment has been minimized.
This comment has been minimized.
|
I've updated the text to simply assume that Extend uses IntoIterator. I am currently testing a patch to do exactly that. |
This comment has been minimized.
This comment has been minimized.
|
I started writing a patch for this, and it now occurs to me that we could instead provide these blanket impls and call it a day:
This would reduce distributable bloat, and also just be less work. Also gives free impls to everyone. Haven't tested that this doesn't conflict with some coherence. |
This comment has been minimized.
This comment has been minimized.
|
Compiler rejects those blankets as conflicting with the concrete implementations. |
This comment has been minimized.
This comment has been minimized.
reem
commented
Feb 21, 2015
|
I'm not sure if I like the implicit Clones that occur here, we don't have a lot of precedent for that with Iterator operations. I'd rather type |
This comment has been minimized.
This comment has been minimized.
|
@reem would you be happy if this was restricted to Copy? |
This comment has been minimized.
This comment has been minimized.
reem
commented
Feb 22, 2015
|
Sure. We have extreme precedent for implicit Copy but less for implicit Clone, especially as relates to iterators. EDIT: Cleanup email mess. |
This comment has been minimized.
This comment has been minimized.
Ryman
commented
Feb 24, 2015
|
+1 for restricting to Copy instead of Clone |
This comment has been minimized.
This comment has been minimized.
|
Hm, I'm not sure I agree about the implicit |
nrc
assigned
alexcrichton
Feb 26, 2015
This comment has been minimized.
This comment has been minimized.
|
So now that we're taking // before this RFC
foo.extend([1, 2, 3].iter().cloned());
foo.extend(borrowed_hash_set.iter().cloned());
foo.extend(owned_hash_set);
// after this RFC
foo.extend(&[1, 2, 3]);
foo.extend(borrowed_hash_set);
foo.extend(owned_hash_set)I think that I personally find the "noise level" tolerable, but an interesting data point I just thought of was that if we allow this sort of "clone without writing clone" then it seems that we should seriously consider implicit cloning on All that basically surmounts of me thinking that we should tread carefully into the domain of "cloning without |
This comment has been minimized.
This comment has been minimized.
|
I've added Copy-only as an explicit alternative. |
This comment has been minimized.
This comment has been minimized.
To push back on this a little bit, it's far from the case that explicit client-side OTOH, usually it's pretty obvious from the types involved in methods like this whether a clone is involved. If I'm appending an iterator over So for me, the guideline about I would vote for a |
This comment has been minimized.
This comment has been minimized.
|
I'd say it's pretty easy to miss in the context of gluing code together. An errant Worse for a newbie, they don't have the compiler slap them on the wrist for getting their ownership wrong. It just chugs along fine. This is totally fine for Copy types though. The semantic and performance difference between T and *&T for Copy types is basically nil in the case of Extend. |
This comment has been minimized.
This comment has been minimized.
|
Hm, I find both @aturon and @Gankro convincing.
This is a good point, but I'm also somewhat wary in that
I do agree that it's easy to start Definitely seems like a fine line here! I think I'm leaning more towards |
This comment has been minimized.
This comment has been minimized.
|
I think this is mostly fine, locally: that is, assuming the rest of the program is correct, and you have the task "add these elements to this data structure", then However, a lot of the time, the rest of the program isn't correct, e.g. function signatures may not be taking ownership where they should be. Having this lots of implicit copying will disguise these points in a design that can be improved, by not forcing the ownership to be explicit in the code. I'm not sure what balance between local ergonomics and global ergonomics suits Rust best. |
Gankro
changed the title
Have collections impl Extend<&T> where T: Clone
Have collections impl Extend<&T> where T: Copy
Mar 17, 2015
Gankro
changed the title
Have collections impl Extend<&T> where T: Copy
Have collections impl Extend<&T> where T: Clone
May 21, 2015
This comment has been minimized.
This comment has been minimized.
|
From discussion in #rust-libs: we realized that there are some interesting ramifications in the generic programming context. In particular, if you bound by To me, this suggests that this should actually be a distinct method -- we could consider making it a defaulted method on the |
This comment has been minimized.
This comment has been minimized.
|
Some follow-up on the previous comment, via @bluss: the generic code itself probably wouldn't be able to tell the difference without an additional bound (that allowed it to read out of the collection). That bound would distinguish the two cases. Nevertheless, providing a separate defaulted method could help resolve the |
This comment has been minimized.
This comment has been minimized.
|
This of course can't work for both Maps and Sequences &T vs (&K, &V). Sequences are arguably more desirable? |
This comment has been minimized.
This comment has been minimized.
We could have an associated type, but that might be going too far. (Or of course a separate trait, but that has discoverability and complexity downsides.) |
This comment has been minimized.
This comment has been minimized.
|
I agree that something like this is necessary, as the current |
This comment has been minimized.
This comment has been minimized.
|
Personally I think this idea has too many issues with it. It makes some concrete case more ergonomic, but adds some curiosities in the generic context and raises the issue of how expensive an implicit OP can be. I'd advise closing this RFC pending letting the language/ecosystem mature more, unless people vociferously demand this ASAP. |
This comment has been minimized.
This comment has been minimized.
|
I think I come down close to where @Gankro is. A separate |
This comment has been minimized.
This comment has been minimized.
|
So to expand on my comment:
Unless we propose upgrading |
This comment has been minimized.
This comment has been minimized.
|
@Gankro Nevermind, you're right: you'd need HKT to make that work. There's still the option of a separate trait, though. |
This comment has been minimized.
This comment has been minimized.
|
What is wrong with the fact that 'pushing' &Ts to a Vec would be different from pushing &Ts to a Vec<&T>? Surely no one expects a Vec to take in an &T without duplicating it? I think I'm not understanding the implications of the fact that a generic bounded by Extend<&'a T> would implement different behavior depending on the parameter? Every implementation has different behavior. |
This comment has been minimized.
This comment has been minimized.
|
So this is my current stance on this RFC:
Therefore I lean to merging this RFC with the text changed to s/Clone/Copy (and adjust the text around push_all accordingly), with an eye to upgrading to Clone in the future once we've had some time to "test the waters". (You can see in the PR history that I kept starting to do this and then waffling as I started to edit the text) |
This comment has been minimized.
This comment has been minimized.
|
Oh, in case it wasn't clear, this RFC has entered its Final Comment Period as of yesterday. |
alexcrichton
added
the
final-comment-period
label
May 27, 2015
This comment has been minimized.
This comment has been minimized.
|
@Gankro |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
Thumbs up, bstrie needs ergonomy badly |
Gankro
changed the title
Have collections impl Extend<&T> where T: Clone
Have collections impl Extend<&T> where T: copy
Jun 1, 2015
This comment has been minimized.
This comment has been minimized.
|
I have updated the text of the RFC to reflect the agreed upon design, and why it was taken. |
This comment has been minimized.
This comment has been minimized.
Ryman
commented on text/0000-embrace-extend-extinguish.md in 8e7f04f
Jun 1, 2015
|
extend => expect in the first line? |
This comment has been minimized.
This comment has been minimized.
|
haha, good catch :) |
This comment has been minimized.
This comment has been minimized.
|
This RFC appears to have quite broad consensus at this point, so I'm going to merge it. The extension of moving the bound from Thanks again for the RFC @Gankro! |
Gankro commentedFeb 14, 2015
Make all collections
impl<'a, T: Copy> Extend<&'a T>.This enables both
vec.extend(&[1, 2, 3]), andvec.extend(&hash_set_of_ints). This provides a more expressive replacement forVec::push_allwith literally no ergonomic loss, while leveraging established APIs.rendered