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 uplibs: Add borrow module, deprecate _equiv and friends #18910
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Note that the design here is somewhat different than the one in the RFC. This was necessary in order to overcome some language limitations: using This will be noted in the tracking issue, and made part of a general amendment to the RFC with implementation tweaks. |
This comment has been minimized.
This comment has been minimized.
|
Also, the deprecation of |
This comment has been minimized.
This comment has been minimized.
|
Nifty. |
aturon
force-pushed the
aturon:borrow-traits
branch
from
6c23d67
to
c0e7a32
Nov 13, 2014
This comment has been minimized.
This comment has been minimized.
|
Another note: the RFC did not mention generalizing the indexing notation using the borrow traits, but of course that only makes sense. This PR does that as well. (Thanks @nikomatsakis for pointing out that it should.) |
alexcrichton
reviewed
Nov 13, 2014
| pub fn get(&self, key: &K) -> Option<&V> { | ||
| tree_find_with(&self.root, |k2| key.cmp(k2)) | ||
| pub fn get<Sized? Q>(&self, key: &Q) -> Option<&V> | ||
| where Q: BorrowFrom<K> + Ord { |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Nov 13, 2014
Member
This is an interesting stylistic precedent to line up the where and fn keywords, I would have expected the alignment of where to match the alignment of -> if it came on the next line which I thought was the ( in the argument list.
This comment has been minimized.
This comment has been minimized.
aturon
Nov 13, 2014
Author
Member
Yeah, I know :-) generally we need to actually firm up all our style conventions, but that's of course lower priority than API issues. I'm happy to go with your recommended style here.
This comment has been minimized.
This comment has been minimized.
Gankro
Nov 13, 2014
Contributor
Personally I'd just do a double-indent, like a normal line continuation.
alexcrichton
reviewed
Nov 13, 2014
| @@ -95,7 +95,7 @@ impl<T: Writer+Send> Terminal<T> for TerminfoTerminal<T> { | |||
| if self.num_colors > color { | |||
| let s = expand(self.ti | |||
| .strings | |||
| .find_equiv("setab") | |||
| .get("setab") | |||
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Is there a reason you chose |
Gankro
reviewed
Nov 13, 2014
| } | ||
|
|
||
| #[unstable = "trait is unstable"] | ||
| impl<T> BorrowFromMut<Vec<T>> for [T] { |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Thiez
Nov 13, 2014
Contributor
Since the BorrowFrom and BorrowFromMut traits are in libcore, they cannot implement for Vec there. Sincce these implementations can't be anywhere else, surely this is the right place?
This comment has been minimized.
This comment has been minimized.
aturon
Nov 13, 2014
Author
Member
They could be in the vec module in libcollections. I put them here because they are being applied to the slice type, and I feel like putting impls in the module defining their Self type is a good default.
This comment has been minimized.
This comment has been minimized.
|
@aturon it occurs to me that we may be able to implement |
Gankro
reviewed
Nov 13, 2014
| //! | ||
| //! Some types make it possible to go from borrowed to owned, usually by | ||
| //! implementing the `Clone` trait. But `Clone` works only for going from `&T` | ||
| //! to `T`. The `ToOwned` trait generalizes `Clone` to contruct owned data |
This comment has been minimized.
This comment has been minimized.
Gankro
reviewed
Nov 13, 2014
| //! pub trait BorrowFrom<Owned> for Sized? { | ||
| //! /// Immutably borrow from an owned value. | ||
| //! fn borrow_from(owned: &Owned) -> &Self; | ||
| //! } |
This comment has been minimized.
This comment has been minimized.
Gankro
Nov 13, 2014
Contributor
It seems weird to duplicate the trait and enum definitions in the docs themselves?
Gankro
reviewed
Nov 13, 2014
| //! ``` | ||
| //! | ||
| //! `Cow` implements both `Deref` and `DerefMut`, which means that you can call | ||
| //! methods directly on the data it encloses. The first type a mutable reference |
This comment has been minimized.
This comment has been minimized.
Gankro
reviewed
Nov 13, 2014
| use ops::{Deref, DerefMut}; | ||
|
|
||
| /// A trait for borrowing data. | ||
| pub trait BorrowFrom<Owned> for Sized? { |
This comment has been minimized.
This comment has been minimized.
Gankro
reviewed
Nov 13, 2014
| } | ||
|
|
||
| /// A clone-on-write smart pointer. | ||
| pub enum Cow<'a, T, B: 'a> where B: ToOwned<T> { |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
aturon
Nov 13, 2014
Author
Member
I debated making this a newtype. That's probably the more conservative thing to do, but then we'd need to separately expose constructors. Either way is fine by me.
This comment has been minimized.
This comment has been minimized.
Gankro
Nov 13, 2014
Contributor
Hmm... unsure. I feel like newtyping is "the right thing", but I dunno. It's unstable so I think we can leave it like this for now, and revisit this for stabilization.
This comment has been minimized.
This comment has been minimized.
|
@alexcrichton Note the comments above re: differences from the RFC. |
This comment has been minimized.
This comment has been minimized.
Yes! That's very much the plan. Note that the blanket impl implicitly requires sized types, which is enough to avoid the overlap. |
Gankro
reviewed
Nov 13, 2014
| fn borrow_from(owned: &T) -> &T { owned } | ||
| } | ||
|
|
||
| impl BorrowFrom<&'static str> for str { |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
gereeter
Nov 13, 2014
Contributor
This allows you to use things like HashMap<&'static str, T> effectively. However, I don't see any reason to not generalize this to impl<'a, Sized? T> BorrowFrom<&'a T> for T.
This comment has been minimized.
This comment has been minimized.
gereeter
Nov 13, 2014
Contributor
Note: there was an issue a while ago (that I just spent far too long failing to find) about the fact that there was no good way to use data structures keyed on reference types like &'static str.
Gankro
reviewed
Nov 13, 2014
| /// Acquire a mutable reference to the owned form of the data. | ||
| /// | ||
| /// Copies the data if it is not already owned. | ||
| pub fn to_owned_mut(&mut self) -> &mut T { |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
aturon
Nov 13, 2014
Author
Member
Yes. This gives you a mutable reference to the owned type, not the borrowed type, which you can't get otherwise -- and does so without destroying the Cow pointer itself.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
aturon
Nov 13, 2014
Author
Member
No, the types are different. deref_mut gives you &mut Borrowed, this gives you &mut Owned.
This comment has been minimized.
This comment has been minimized.
aturon
Nov 13, 2014
Author
Member
And there's no way to change deref_mut to give you this type, because it must yield the same underlying type as deref does, which we definitely want to be borrowed (since we don't want it to require an owned copy).
This comment has been minimized.
This comment has been minimized.
|
\o/ This is wonderful! |
gereeter
reviewed
Nov 13, 2014
| fn borrow_from_mut(owned: &mut Owned) -> &mut Self; | ||
| } | ||
|
|
||
| impl<T: Sized> BorrowFrom<T> for T { |
This comment has been minimized.
This comment has been minimized.
gereeter
Nov 13, 2014
Contributor
I know that the RFC said to use T: Sized here to prevent overlap with the other impls, but now that we have multidispatch this shouldn't be a problem, right?
gereeter
reviewed
Nov 13, 2014
| @@ -283,7 +284,7 @@ pub struct HashMap<K, V, H = RandomSipHasher> { | |||
| } | |||
|
|
|||
| /// Search for a pre-hashed key. | |||
| fn search_hashed_generic<K, V, M: Deref<RawTable<K, V>>>(table: M, | |||
| fn search_hashed<K, V, M: Deref<RawTable<K, V>>>(table: M, | |||
| hash: &SafeHash, | |||
This comment has been minimized.
This comment has been minimized.
gereeter
Nov 13, 2014
Contributor
This breaks the alignment of the arguments. Should they be realigned?
This comment has been minimized.
This comment has been minimized.
|
You seem to have forgotten btree. |
This comment has been minimized.
This comment has been minimized.
|
Possible thing to include: tuple of Owned -> tuple of Borrowed impls. |
SimonSapin
reviewed
Nov 13, 2014
| @@ -1045,7 +997,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { | |||
| /// assert_eq!(map.get(&2), None); | |||
| /// ``` | |||
| #[unstable = "matches collection reform specification, waiting for dust to settle"] | |||
| pub fn get(&self, k: &K) -> Option<&V> { | |||
| pub fn get<Sized? Q>(&self, k: &Q) -> Option<&V> where Q: Hash<S> + Eq + BorrowFrom<K> { | |||
This comment has been minimized.
This comment has been minimized.
SimonSapin
Nov 13, 2014
Contributor
If I understand correctly, this assumes that the implementations of Hash and Eq for Q and K are compatible, right? That is, for any k1 and k2 of type K:
let q1: Q = BorrowFrom::borrow_from(k1);
let q2: Q = BorrowFrom::borrow_from(k2);
assert_eq!(make_hash(q1), make_hash(k1));
assert_eq!(q1 == q2, k1 == k2);That invariant unfortunately doesn’t seem like it can be enforced by the type system, but maybe it should be documented?
The problem was the same with Equiv. We ran into it in Servo when trying to make hashing of interned strings O(1) by only hashing the internal u64.
This comment has been minimized.
This comment has been minimized.
aturon
Nov 13, 2014
Author
Member
Yes, this was a tradeoff brought up in the RFC. It's possible to enforce this invariant, but at some loss in flexibility: it would force you to consistently use a single kind of borrowed value for lookups.
Agreed about documentation.
aturon
force-pushed the
aturon:borrow-traits
branch
3 times, most recently
from
b55a578
to
9c9615a
Nov 13, 2014
This comment has been minimized.
This comment has been minimized.
|
Pushed a new version; I believe I've addressed all comments. |
This comment has been minimized.
This comment has been minimized.
|
Any way Cow could not be done through deref(mut)? It was pointed out on IRC that this would be Rust's first "costly" use of those traits, which at least to me seems like it's sufficient to negate the syntactic simplicity of magic. |
This comment has been minimized.
This comment has been minimized.
|
@thestinger with rust-lang/rfcs#439 we'll have a trait definition that looks like: pub trait Ord<Rhs = Self>: Eq<Rhs> + PartialOrd<Rhs> {
fn cmp(&self, other: &Rhs) -> Ordering;
}in which case I think we can leverage the impl<K, V> TreeMap<K, V> {
fn get<Q>(&self, q: &Q) -> Option<&V> where K: Ord<Q> { /* ... */ }
}
impl<T, U: BorrowFrom<T>> Ord<U> for T { /* ... */ }I'm not entirely sure how much coherence would disallow, but it seems like it should be possible. |
This comment has been minimized.
This comment has been minimized.
|
@pythonesque yes, you're right, supporting |
aturon
force-pushed the
aturon:borrow-traits
branch
from
9c9615a
to
bbc53d7
Nov 14, 2014
This comment has been minimized.
This comment has been minimized.
|
@pythonesque I've removed the @thestinger I reinstated the @alexcrichton re-r? |
This comment has been minimized.
This comment has been minimized.
|
@aturon: Thanks, I'm in full agreement with this pull request then. |
bors
added a commit
that referenced
this pull request
Nov 16, 2014
aturon
force-pushed the
aturon:borrow-traits
branch
from
bbc53d7
to
2174e57
Nov 16, 2014
bors
added a commit
that referenced
this pull request
Nov 16, 2014
aturon
force-pushed the
aturon:borrow-traits
branch
from
2174e57
to
7cf8589
Nov 16, 2014
bors
added a commit
that referenced
this pull request
Nov 17, 2014
aturon
force-pushed the
aturon:borrow-traits
branch
from
7cf8589
to
1d88e73
Nov 17, 2014
bors
added a commit
that referenced
this pull request
Nov 17, 2014
aturon
force-pushed the
aturon:borrow-traits
branch
2 times, most recently
from
168d74a
to
a8a8b23
Nov 17, 2014
bors
added a commit
that referenced
this pull request
Nov 17, 2014
bors
added a commit
that referenced
this pull request
Nov 17, 2014
TeXitoi
reviewed
Nov 17, 2014
| /// A generalization of Clone to borrowed data. | ||
| pub trait ToOwned<Owned> for Sized?: BorrowFrom<Owned> { | ||
| /// Create owned data from borrowed data, usually by copying. | ||
| fn to_owned(&self) -> Owned; |
This comment has been minimized.
This comment has been minimized.
TeXitoi
Nov 17, 2014
Contributor
Why to_owned must takes a reference?
I think that HashMap::entry() can take a ToOwned<K> as key, and create a owned object if needed. But to have that to work, we should have to_owned taking self to allow T: ToOwned<T> to just move.
Example: http://is.gd/YORUei
I didn't tried to modify this pull request with this change, so maybe there is problem in Cow with this change.
aturon
added some commits
Nov 12, 2014
aturon
force-pushed the
aturon:borrow-traits
branch
from
375b205
to
46be8eb
Nov 17, 2014
This comment has been minimized.
This comment has been minimized.
|
r=alexcrichton |
aturon commentedNov 13, 2014
Following the collections reform RFC, this PR:
borrowmodule to libcore. The module contains traits for borrowing data (BorrowFromandBorrowFromMut), generalized cloning (ToOwned), and a clone-on-write smartpointer (Cow)._equivfamily of methods onHashMapandHashSetby instead generalizing the "normal" methods likegetandremoveto use the newstd::borrowinfrastructure.TreeMap,TreeSet,BTreeMapandBTreeSetto use the newstd::borrowinfrastructure for lookups.[breaking-change]