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

libs: Add borrow module, deprecate _equiv and friends #18910

Merged
merged 7 commits into from Nov 18, 2014

Conversation

Projects
None yet
@aturon
Copy link
Member

aturon commented Nov 13, 2014

Following the collections reform RFC, 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

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 13, 2014

cc #18424
cc @Gankro

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 13, 2014

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 Borrow instead of BorrowFrom requires full method-level where clauses, which are not yet available.

This will be noted in the tracking issue, and made part of a general amendment to the RFC with implementation tweaks.

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 13, 2014

Also, the deprecation of MaybeOwned in favor of Cow will be left for follow-up work.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Nov 13, 2014

Nifty.

@aturon aturon force-pushed the aturon:borrow-traits branch from 6c23d67 to c0e7a32 Nov 13, 2014

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 13, 2014

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.)

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.

@alexcrichton

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.

@aturon

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.

@Gankro

Gankro Nov 13, 2014

Contributor

Personally I'd just do a double-indent, like a normal line continuation.

@@ -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.

@alexcrichton

alexcrichton Nov 13, 2014

Member

These diffs make me happy.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Nov 13, 2014

Is there a reason you chose BorrowFrom{,Mut} instead of Borrow{,Mut}? (like in the RFC)

}

#[unstable = "trait is unstable"]
impl<T> BorrowFromMut<Vec<T>> for [T] {

This comment has been minimized.

@Gankro

Gankro Nov 13, 2014

Contributor

Should these be in vec.rs? Genuinely unsure.

This comment has been minimized.

@Thiez

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.

@aturon

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.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Nov 13, 2014

@aturon it occurs to me that we may be able to implement PathBuf : BorrowFrom<Path> and thus have a hashmap keyed on PathBuf be indexable with a Path. The blanket impl wouldn't conflict because it requires that the two types be equal, and PathBuf != Path. I'm not sure how it would interact with inference.

//!
//! 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.

@Gankro

Gankro Nov 13, 2014

Contributor

s/contruct/construct

//! pub trait BorrowFrom<Owned> for Sized? {
//! /// Immutably borrow from an owned value.
//! fn borrow_from(owned: &Owned) -> &Self;
//! }

This comment has been minimized.

@Gankro

Gankro Nov 13, 2014

Contributor

It seems weird to duplicate the trait and enum definitions in the docs themselves?

//! ```
//!
//! `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.

@Gankro

Gankro Nov 13, 2014

Contributor

s/type/time

use ops::{Deref, DerefMut};

/// A trait for borrowing data.
pub trait BorrowFrom<Owned> for Sized? {

This comment has been minimized.

@Gankro

Gankro Nov 13, 2014

Contributor

Any reason to use Owned here and T in the impl?

}

/// A clone-on-write smart pointer.
pub enum Cow<'a, T, B: 'a> where B: ToOwned<T> {

This comment has been minimized.

@Gankro

Gankro Nov 13, 2014

Contributor

Do we want people to be able to match on the internals of this?

This comment has been minimized.

@aturon

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.

@Gankro

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.

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 13, 2014

@alexcrichton Note the comments above re: differences from the RFC.

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 13, 2014

@nikomatsakis

@aturon it occurs to me that we may be able to implement PathBuf : BorrowFrom<Path> and thus have a hashmap keyed on PathBuf be indexable with a Path. The blanket impl wouldn't conflict because it requires that the two types be equal, and PathBuf != Path. I'm not sure how it would interact with inference.

Yes! That's very much the plan. Note that the blanket impl implicitly requires sized types, which is enough to avoid the overlap.

fn borrow_from(owned: &T) -> &T { owned }
}

impl BorrowFrom<&'static str> for str {

This comment has been minimized.

@Gankro

Gankro Nov 13, 2014

Contributor

What is this necessary for?

This comment has been minimized.

@gereeter

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.

@gereeter

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.

/// 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.

@Gankro

Gankro Nov 13, 2014

Contributor

Any reason to make this public?

This comment has been minimized.

@aturon

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.

@SimonSapin

SimonSapin Nov 13, 2014

Contributor

Doesn't deref_mut do the same?

This comment has been minimized.

@aturon

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.

@aturon

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).

@Gankro

This comment has been minimized.

Copy link
Contributor

Gankro commented Nov 13, 2014

\o/ This is wonderful! 😍

fn borrow_from_mut(owned: &mut Owned) -> &mut Self;
}

impl<T: Sized> BorrowFrom<T> for T {

This comment has been minimized.

@gereeter

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?

@@ -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.

@gereeter

gereeter Nov 13, 2014

Contributor

This breaks the alignment of the arguments. Should they be realigned?

@Gankro

This comment has been minimized.

Copy link
Contributor

Gankro commented Nov 13, 2014

You seem to have forgotten btree.

@Gankro

This comment has been minimized.

Copy link
Contributor

Gankro commented Nov 13, 2014

Possible thing to include: tuple of Owned -> tuple of Borrowed impls.

@@ -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.

@SimonSapin

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.

@aturon

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 aturon force-pushed the aturon:borrow-traits branch 3 times, most recently from b55a578 to 9c9615a Nov 13, 2014

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 14, 2014

@Gankro @alexcrichton

Pushed a new version; I believe I've addressed all comments.

@pythonesque

This comment has been minimized.

Copy link
Contributor

pythonesque commented Nov 14, 2014

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.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Nov 14, 2014

@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 Rhs type parameter to compare any type to the key type:

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.

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 14, 2014

@pythonesque yes, you're right, supporting DerefMut here does not fit will with our general strategy of making things like clone explicit. (Deref is fine.) I will revise.

@aturon aturon force-pushed the aturon:borrow-traits branch from 9c9615a to bbc53d7 Nov 14, 2014

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 14, 2014

@pythonesque I've removed the DerefMut impl.

@thestinger I reinstated the find_with methods as #[experimental]; I have no objection to keeping them around under that status for now.

@alexcrichton re-r?

@thestinger

This comment has been minimized.

Copy link
Contributor

thestinger commented Nov 14, 2014

@aturon: Thanks, I'm in full agreement with this pull request then.

bors added a commit 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 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

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 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

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 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

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 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

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 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]
/// 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.

@TeXitoi

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

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`).
libcollections: use BorrowFrom in TreeSet, Map
This commit generalizes methods like `get` and `remove` for `TreeMap`
and `TreeSet` to use the new `std::borrow` infrastructure.

[breaking-change]
libstd: Deprecate _equiv methods
This commit 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.

[breaking-change]
Fallout from deprecation
This commit handles the fallout from deprecating `_with` and `_equiv` methods.
libcollections: generalize BTree* to use BorrowFrom
Generalizes the BTree-based collections to use the new BorrowFrom
infrastructure for more flexible lookups and removals.

@aturon aturon force-pushed the aturon:borrow-traits branch from 375b205 to 46be8eb Nov 17, 2014

@aturon

This comment has been minimized.

Copy link
Owner Author

aturon commented on 46be8eb Nov 17, 2014

r=alexcrichton

@bors bors merged commit 46be8eb into rust-lang:master Nov 18, 2014

1 check passed

continuous-integration/travis-ci The Travis CI build passed
Details

@alexcrichton alexcrichton referenced this pull request Nov 18, 2014

Closed

Implement collections reform #18424

23 of 24 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.