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

Add generic conversion traits #23538

Closed
wants to merge 1 commit into from

Conversation

Projects
None yet
4 participants
@aturon
Copy link
Member

aturon commented Mar 20, 2015

This commit:

  • Introduces std::convert, providing an implementation of
    RFC 529.

  • Deprecates the AsPath, AsOsStr, and IntoBytes traits, all
    in favor of the corresponding generic conversion traits.

    Consequently, various IO APIs now take As<Path> rather than
    AsPath, and so on. Since the types provided by std implement both
    traits, this should cause relatively little breakage.

  • Deprecates many from_foo constructors in favor of from.

  • Changes PathBuf::new to take no argument (creating an empty buffer,
    as per convention). The previous behavior is now available as
    PathBuf::from.

  • De-stabilizes IntoCow. It's not clear whether we need this separate trait.

Closes #14433
Closes #22751

[breaking-change]

r? @alexcrichton
cc @Gankro @erickt @cmr

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Mar 20, 2015

PRELIMINARY PR: Do not merge until the RFC is approved.

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Mar 20, 2015

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Mar 20, 2015

Per IRC: @alexcrichton is very uncomfortable with these living in libcollections rather than libcore. This placement was to facilitate impls like impl<T: Clone> To<Vec<T>> for [T] which would otherwise be disallowed due to coherence.

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Mar 20, 2015

cc @reem

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Mar 20, 2015

Per IRC: @reem points out that the same coherence problems make it much more difficult to define "implicit conversions" via generics targetting user-land types: you cannot implement To<MyType<T>> for StdType<T> due to coherence.

Introducing an ad hoc conversion trait, on the other hand, makes it possible to do this in userland.

@aturon aturon force-pushed the aturon:conversion branch from 9fcd79f to 844c115 Mar 20, 2015

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Mar 20, 2015

Updated: I've now moved the traits into libcore, and have a (rather sad) impl of To<Vec<u8>> for [u8] which coherence permits.

@aturon aturon force-pushed the aturon:conversion branch 6 times, most recently from c8671be to 3c62067 Mar 20, 2015

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Mar 20, 2015

☔️ The latest upstream changes (presumably #23548) made this pull request unmergeable. Please resolve the merge conflicts.

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Mar 20, 2015

I believe this is now ready to go, once the RFC itself has been merged.

@@ -14,6 +14,7 @@

use core::clone::Clone;
use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use core::convert::As;

This comment has been minimized.

@alexcrichton

alexcrichton Mar 20, 2015

Member

Could these traits also go into the libcore prelude? I think files like this can have use core::prelude::* at the top as well (slowly been migrating over time).

/// A cheap, reference-to-reference conversion.
pub trait As<T: ?Sized> {
/// Perform the conversion.
fn convert_as(&self) -> &T;

This comment has been minimized.

@alexcrichton

alexcrichton Mar 20, 2015

Member

I do quite like your suggestions on the RFC of as_ref, as_mut, to, and into. The only one that's "wrong" is as_ref (e.g. it should be called as) but it seems worth it!

This comment has been minimized.

@Gankro

Gankro Mar 20, 2015

Contributor

Wouldn't as_ref and as_mut conflict with several adhoc methods (thinking of RawPtr and Option off the top of my head)?

This comment has been minimized.

@aturon

aturon Mar 20, 2015

Author Member

They would overlap, but inherent impls trump trait ones. (Still, the overlap is one reason we might not want to choose these names, or might consider renaming the others...)

fn convert_as(&self) -> &[T] {
self.as_slice()
}
}

This comment has been minimized.

@alexcrichton

alexcrichton Mar 20, 2015

Member

I thought we've been pretty hesitant about this in the past? Slices from Option and Result I thought would continue to be unstable functionality.

This comment has been minimized.

@aturon

aturon Mar 20, 2015

Author Member

I'm willing to mark this unstable, but personally I have no objection to this functionality, especially in the context of generic conversions.

This comment has been minimized.

@alexcrichton

alexcrichton Mar 20, 2015

Member

My fear in marking these unstable is that there's no warning on usage of an unstable impl, only on an unstable trait, and it's not clear that we'll get it fixed for 1.0.


/// Convert from `Option<T>` to `&[T]` (without copying)
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]

This comment has been minimized.

@alexcrichton

alexcrichton Mar 20, 2015

Member

I would personally prefer this continue to remain unstable

This comment has been minimized.

@alexcrichton

alexcrichton Mar 20, 2015

Member

(same for Result)

This comment has been minimized.

@alexcrichton

alexcrichton Mar 23, 2015

Member

ping, perhaps this could remain unstable?

@@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::convert::From;

This comment has been minimized.

@alexcrichton

alexcrichton Mar 20, 2015

Member

This should be in the prelude, right?

This comment has been minimized.

@alexcrichton

alexcrichton Mar 20, 2015

Member

(same for a few files below)

This comment has been minimized.

@aturon

aturon Mar 20, 2015

Author Member

It's in the prelude, yes; I probably added a few redundant imports mechanically.

This comment has been minimized.

@alexcrichton
}

#[stable(feature = "rust1", since = "1.0.0")]
impl From<String> for OsString {

This comment has been minimized.

@alexcrichton

alexcrichton Mar 20, 2015

Member

I wonder if these would be better expressed as Into? For example functions may want to take T: Into<OsString>.

@@ -999,16 +1036,58 @@ impl PathBuf {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<P: AsPath> iter::FromIterator<P> for PathBuf {
impl<'a> From<&'a str> for PathBuf {

This comment has been minimized.

@alexcrichton

alexcrichton Mar 20, 2015

Member

Similarly to the OsString case, these may be better expressed via Into.

It's also a little sad that the same set of impls as From<T> for OsString needs to be listed here, but not necessarily the end of the world.

This comment has been minimized.

@aturon

aturon Mar 20, 2015

Author Member

Yes, the inability to do blanket "transportation" of one conversion to another is a loss here.

Note that specialization may someday allow us to regain this via automatic reflexive and transitive blankets. It's not clear.

This comment has been minimized.

@alexcrichton

alexcrichton Mar 20, 2015

Member

Yeah I'm willing to just understand that this is a fact of life :)

None => {
if parse_name_directive(line, "pp-exact") {
testfile.file_name().map(|s| PathBuf::new(s))
testfile.file_name().map(|s| PathBuf::from(s))

This comment has been minimized.

@Gankro

Gankro Mar 20, 2015

Contributor

This can just be map(PathBuf::from)

let mut result = Vec::with_capacity(size + self.len());
let mut first = true;
for v in self {
if first { first = false } else { result.push(sep.clone()) }
result.push_all(v.as_slice())
result.push_all(v.convert_as())

This comment has been minimized.

@Gankro

Gankro Mar 20, 2015

Contributor

This is kind of an unfortunate readability loss.

This comment has been minimized.

@aturon

aturon Mar 20, 2015

Author Member

Yeah, it's probably more clear to perform the conversion up-front and rebind the variable (perhaps with type annotation, even).

This comment has been minimized.

@alexcrichton

alexcrichton Mar 20, 2015

Member

Note, though, that v.as_ref::<[_]>() would probably still be readable.

This comment has been minimized.

@Gankro

Gankro Mar 20, 2015

Contributor

Alternatively if these traits were hooked into coercions you could just result.push_all(&v), which is less informative but somehow less cryptic than covert_as::<???>().

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Mar 20, 2015

cc #23567

@aturon aturon force-pushed the aturon:conversion branch from 3c62067 to dbd9480 Mar 23, 2015

@aturon aturon changed the title [WIP] Add generic conversion traits Add generic conversion traits Mar 23, 2015

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Mar 23, 2015

Updated:

  • Removed To for the time being.

  • Renamed As to AsRef.

  • Renamed all methods to match their trait names.

  • All conversion functionality now in libcore; added to core::prelude

  • Added From => Into implementation, which makes it possible to add conversions in both directions without running afoul of coherence. For example, we now have From<[T]> for Vec<T> where T: Clone, which yields the corresponding Into going in the other direction -- despite the fact that the two types live in different crates.

    I also believe this addresses a few concerns about things implementing From instead of Into

  • Removed AsRef impls for slices from Option/Result, which was causing a bad interaction with their as_ref methods. This functionality is available by calling as_slice directly.

All in all, I feel much better with the form this PR is taking now. It feels cleaner, leaner, more consistent and more extensible. Thanks for the feedback making this possible!

@alexcrichton: re-r?

@@ -67,8 +67,8 @@ pub fn current_dir() -> io::Result<PathBuf> {
/// println!("Successfully changed working directory to {}!", root.display());
/// ```
#[stable(feature = "env", since = "1.0.0")]
pub fn set_current_dir<P: AsPath + ?Sized>(p: &P) -> io::Result<()> {
os_imp::chdir(p.as_path())
pub fn set_current_dir<P: AsRef<path::Path> + ?Sized>(p: &P) -> io::Result<()> {

This comment has been minimized.

@alexcrichton

alexcrichton Mar 23, 2015

Member

Could this module import Path directly and use AsRef<Path>?

This comment has been minimized.

@aturon

aturon Mar 23, 2015

Author Member

Ahha! It can now. I think when I first wrote it Path was still in the prelude :)

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Mar 23, 2015

I, too, am quite happy with how this is turning out! r=me with the as_slice methods on Option and Result remaining #[unstable] (as they were before)

@aturon aturon force-pushed the aturon:conversion branch from dbd9480 to a686d27 Mar 23, 2015

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Mar 23, 2015

pings addressed :)

@aturon aturon force-pushed the aturon:conversion branch from a686d27 to 8389253 Mar 23, 2015

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Mar 23, 2015

@aturon aturon force-pushed the aturon:conversion branch from 8389253 to 97c8e43 Mar 23, 2015

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Mar 23, 2015

@bors: r=alexcrichton 97c8e43

alexcrichton added a commit to alexcrichton/rust that referenced this pull request Mar 23, 2015

rollup merge of rust-lang#23538: aturon/conversion
Conflicts:
	src/librustc_back/rpath.rs

@aturon aturon force-pushed the aturon:conversion branch from 97c8e43 to 08ee682 Mar 23, 2015

Add generic conversion traits
This commit:

* Introduces `std::convert`, providing an implementation of
RFC 529.

* Deprecates the `AsPath`, `AsOsStr`, and `IntoBytes` traits, all
in favor of the corresponding generic conversion traits.

  Consequently, various IO APIs now take `AsRef<Path>` rather than
`AsPath`, and so on. Since the types provided by `std` implement both
traits, this should cause relatively little breakage.

* Deprecates many `from_foo` constructors in favor of `from`.

* Changes `PathBuf::new` to take no argument (creating an empty buffer,
  as per convention). The previous behavior is now available as
  `PathBuf::from`.

* De-stabilizes `IntoCow`. It's not clear whether we need this separate trait.

Closes #22751
Closes #14433

[breaking-change]
@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Mar 24, 2015

Rolled into #23654

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Mar 24, 2015

☔️ The latest upstream changes (presumably #23654) made this pull request unmergeable. Please resolve the merge conflicts.

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.