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

std: Stabilize the ascii module #22024

Merged
merged 2 commits into from
Feb 18, 2015
Merged

std: Stabilize the ascii module #22024

merged 2 commits into from
Feb 18, 2015

Conversation

alexcrichton
Copy link
Member

  • Move the type parameter on the AsciiExt trait to an associated type named
    Owned.
  • Move ascii::escape_default to using an iterator.

This is a breaking change due to the removal of the type parameter on the
AsciiExt trait as well as the modifications to the escape_default function
to returning an iterator. Manual implementations of AsciiExt (or AsciiExt
bounds) should be adjusted to remove the type parameter and using the new
escape_default should be relatively straightforward.

[breaking-change]

@alexcrichton
Copy link
Member Author

cc @SimonSapin

r? @aturon

@rust-highfive rust-highfive assigned aturon and unassigned brson Feb 6, 2015
@rust-highfive
Copy link
Collaborator

r? @brson

(rust_highfive has picked a reviewer for you, use r? to override)

@aturon aturon mentioned this pull request Feb 6, 2015
38 tasks
@alexcrichton
Copy link
Member Author

Note that this does not currently mark the methods/trait as #[stable], somewhat intentionally.

@SimonSapin
Copy link
Contributor

One downside of these changes is that String now has a .eq_ignore_ascii_case(&String) method, which is less flexible than the .eq_ignore_ascii_case(&str) method it has trough Deref to str (which is now shadowed). (Same for Vec<u8> and [u8].) Unfortunately I don’t see how to fix this without keeping two traits.

@SimonSapin
Copy link
Contributor

Implement AsciiExt for all &T where T: AsciiExt.

When is this useful?

@huonw
Copy link
Member

huonw commented Feb 8, 2015

Strictly speaking &String and &str are now equally flexible via std::string::as_string although it is unclear to me if we wish to retain that forever.

@SimonSapin
Copy link
Contributor

@huonw Ok, as_string makes things not impossible, but it’s not very convenient or easy to discover.

@alexcrichton
Copy link
Member Author

One downside of these changes is that String now has a .eq_ignore_ascii_case(&String) method,

Hm that's a good point, I had not considered that. Having two traits isn't necessarily the end of the world, so perhaps this makes it worth it to have. Out of curiosity, do you think that having two vs one trait for this is ok?

Implement AsciiExt for all &T where T: AsciiExt.

I didn't originally have a use for it, but I've been doing it with other common traits (mainly just because it's possible), so I figured I'd throw it in. I'd be find leaving it until later though.

@SimonSapin
Copy link
Contributor

Implement AsciiExt for all &T where T: AsciiExt.

I didn't originally have a use for it, but I've been doing it with other common traits (mainly just because it's possible), so I figured I'd throw it in. I'd be find leaving it until later though.

As far as I can tell, there are two uses for a trait: have it in scope to call methods, and use it as a bound in generics. This impl doesn’t help the former: any method of T can already be called on &T trough Deref. For the latter, I don’t see how having a bound on AsciiExt is useful: this trait is really about providing methods, not describing aspects of a type.

So, although having this impl doesn’t hurt, I’d go with “you ain’t gonna need it”. It can always be added later if needed.

@aturon
Copy link
Member

aturon commented Feb 13, 2015

Sorry for the long delay looking at this.

I like moving to an associated type and iterator, but agree with @SimonSapin on the other points.

@alexcrichton alexcrichton changed the title std: Tidy up the ascii module a bit std: Stabilize the ascii module Feb 17, 2015
@alexcrichton
Copy link
Member Author

I've updated this PR and because the changes are so minor now I've marked all contents as #[stable] as well.

re-r? @SimonSapin and @aturon

@SimonSapin
Copy link
Contributor

Looks good to me.

@aturon
Copy link
Member

aturon commented Feb 17, 2015

So, I'm sorry to be suggesting this so late, but something about this design has always bugged me, and I think I just put my finger on it: the use of the into_ methods at all. Why not instead have mutating variants on &self, and a single AsciiExt trait?

To make this work, we'd need a DerefMut implementation on String -- and a better convention for when we have mutating and copy-creating variants of methods :-)

Thoughts? Am I missing something?

@alexcrichton
Copy link
Member Author

Hm, could you sketch that out a little more concretely? I think we could safely implement DerefMut for String but I'm not sure how it connects to this or how it would help (e.g. you can't safely modify &mut str I believe).

@SimonSapin
Copy link
Contributor

Sure, mutating methods instead of by-value into_ methods would work, they’re equivalent. I don’t really have an opinion on which is preferable.

I don’t think DerefMut is required, the String impl can use .as_mut_vec()

@alexcrichton
Copy link
Member Author

One slightly problem might be that if we have something like fn convert_to_ascii_uppercase(&mut self) then it's uncler to me whether we can provide an impl of AsciiExt on str. I think in terms of memory safety we should be able to, but I'm not sure that &mut str really shows up anywhere else...

@SimonSapin
Copy link
Contributor

These methods would be on the OwnedAsciiExt trait, only implemented for String and Vec<u8>.

@aturon
Copy link
Member

aturon commented Feb 17, 2015

@SimonSapin

Sure, mutating methods instead of by-value into_ methods would work, they’re equivalent. I don’t really have an opinion on which is preferable.

They're not equivalent, because the into methods require full ownership of the data (so you can't use it with e.g. &mut [u8]). This is why these methods stick out like a sore thumb (to me).

I don’t think DerefMut is required, the String impl can use .as_mut_vec()

The idea was to not impl on String/Vec at all, but to work directly on slices. (See sketch below)

@alexcrichton

Hm, could you sketch that out a little more concretely? I think we could safely implement DerefMut for String but I'm not sure how it connects to this or how it would help (e.g. you can't safely modify &mut str I believe).

One slightly problem might be that if we have something like fn convert_to_ascii_uppercase(&mut self) then it's uncler to me whether we can provide an impl of AsciiExt on str. I think in terms of memory safety we should be able to, but I'm not sure that &mut str really shows up anywhere else...

Right, so we don't use &mut str anywhere today because there's relatively little you can do safely with it. But the type is available! And this is a safe use case.

Here's what I have in mind. We have a single trait AsciiExt in ascii, as follows:

pub trait AsciiExt {
    type Owned;
    fn is_ascii(&self) -> bool;
    fn to_ascii_uppercase(&self) -> Owned;
    fn to_ascii_lowercase(&self) -> Owned;
    fn make_ascii_uppercase(&mut self);
    fn make_ascii_lowercase(&mut self);
    fn eq_ignore_ascii_case(&self, other: &Self) -> bool;
}

and this trait would be implemented for: [u8], u8, char, and str only.

For this to work, we need String to DerefMut to str, so that dispatch will automatically deref and find the implementation above. (We could impl on String directly, of course, but that would be redundant.)

@aturon
Copy link
Member

aturon commented Feb 17, 2015

Note: the naming of the methods in the above sketch is a strawman, we badly need a convention here.

@SimonSapin
Copy link
Contributor

Ooh, I see. Yes, that makes sense. And having a single trait is nicer.

@alexcrichton
Copy link
Member Author

How would you guys feel about moving to that today? We could leave OwnedAsciiExt as #[unstable] as well as the make_* methods. That should mean that implementations of AsciiExt are unstable (due to unstable methods) and use of the make_* methods is unstable. All stable methods should be fine to use, however.

@aturon
Copy link
Member

aturon commented Feb 17, 2015

@alexcrichton I'd be fine with that, modulo that I'm not really fond of make_ as a prefix (but am struggling to come up with a good convention).

Previously an implementation of a stable trait allows implementations of
unstable methods. This updates the stability pass to ensure that all items of an
impl block of a trait are indeed stable on the trait itself.
This commit performs a stabilization pass over the `std::ascii` module taking
the following actions:

* the module name is now stable
* `AsciiExt` is now stable after moving its type parameter to an `Owned`
  associated type
* `AsciiExt::is_ascii` is now stable
* `AsciiExt::to_ascii_uppercase` is now stable
* `AsciiExt::to_ascii_lowercase` is now stable
* `AsciiExt::eq_ignore_ascii_case` is now stable
* `AsciiExt::make_ascii_uppercase` is added to possibly replace
  `OwnedAsciiExt::into_ascii_uppercase` (similarly for lowercase variants).
* `escape_default` now returns an iterator and is stable
* `EscapeDefault` is now stable

Trait implementations are now also marked stable.

Primarily it is still unstable to *implement* the `AsciiExt` trait due to it
containing some unstable methods.

[breaking-change]
@alexcrichton
Copy link
Member Author

Ok, updated with mentioned changes, r? @aturon

@aturon
Copy link
Member

aturon commented Feb 17, 2015

@bors: r+ 235f35b

alexcrichton added a commit to alexcrichton/rust that referenced this pull request Feb 17, 2015
* Move the type parameter on the `AsciiExt` trait to an associated type named
  `Owned`.
* Move `ascii::escape_default` to using an iterator.

This is a breaking change due to the removal of the type parameter on the
`AsciiExt` trait as well as the modifications to the `escape_default` function
to returning an iterator. Manual implementations of `AsciiExt` (or `AsciiExt`
bounds) should be adjusted to remove the type parameter and using the new
`escape_default` should be relatively straightforward.

[breaking-change]
@bors
Copy link
Contributor

bors commented Feb 17, 2015

⌛ Testing commit 235f35b with merge 8a91f08...

@bors
Copy link
Contributor

bors commented Feb 18, 2015

💔 Test failed - auto-mac-64-nopt-t

@huonw huonw merged commit 235f35b into rust-lang:master Feb 18, 2015
@aturon aturon mentioned this pull request Feb 18, 2015
91 tasks
@SimonSapin
Copy link
Contributor

Looks like make_ascii_{upper,lower}case landed, but DerefMut<Target=str> for String (which it requires) did not.

http://www.reddit.com/r/rust/comments/2xr7i1/how_to_call_strmake_ascii_uppercasemut_self/

@SimonSapin
Copy link
Contributor

Also, should OwnedAsciiExt be deprecated?

@alexcrichton alexcrichton deleted the ascii branch March 3, 2015 17:21
@alexcrichton
Copy link
Member Author

Looks like make_ascii_{upper,lower}case landed, but DerefMut<Target=str> for String (which it requires) did not.

Yes that is currently intentional. Implementing DerefMut for String is a bit of a bigger decision I'd like to hold off on just yet. This is also why OwnedAsciiExt is not deprecated so there's still a method of consumption during case conversion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants