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

Have From<&str> automatically provide FromStr #2143

Open
mqudsi opened this issue Sep 7, 2017 · 12 comments
Open

Have From<&str> automatically provide FromStr #2143

mqudsi opened this issue Sep 7, 2017 · 12 comments
Labels
T-libs-api Relevant to the library API team, which will review and decide on the RFC.

Comments

@mqudsi
Copy link

mqudsi commented Sep 7, 2017

Currently rust has both the traits std::str::FromStr and std::convert::From<T>, the latter of which is often implemented for T: String even when std::str::FromStr is not.

Can implementing std::str::From<String>/std::str::From<&str> provide a free implementation of std::convert::FromStr so that this problem is avoided? From<&str> (being exception-free) can be used to implement FromStr, even if the converse isn't true.

@mqudsi mqudsi changed the title Obviate FromStr and use From<&String>/From<&str> instead Have FromStr automatically provide From<str> Sep 7, 2017
@mqudsi mqudsi changed the title Have FromStr automatically provide From<str> Have From<&str> automatically provide FromStr Sep 7, 2017
@sfackler
Copy link
Member

sfackler commented Sep 7, 2017

FromStr represents a fallible conversion, and so would correspond more closely to TryFrom rather than From. However, the set of blanket implementations allowed for TryFrom prevent it form replacing FromStr in parse: rust-lang/rust#44174

@mqudsi
Copy link
Author

mqudsi commented Sep 8, 2017

We're going to keep running into problems like this so long as rust doesn't have a way to resolve multiple implementation conflicts :/

Semantically, an infallible conversion is just a special case of fallible conversions, really just a Result<T,!>, if you will. From should provide TryFrom and both should provide FromStr. If #1822 were to be resolved, rust-lang/rust#44174 would automatically take care of this particular issue, though.

Basically, replace FromStr with TryFrom<&str> and then the blanket TryFrom<T> derived from From<T> would provide FromStr in both the fallible and infallible cases.

Edit: corrected swapped From and TryFrom in text.

@DaseinPhaos
Copy link

Semantically, an infallible conversion is just a special case of fallible conversions, really just a Result<T,!>, if you will. TryFrom should provide From...

Perhaps I'm reading this wrong, but if From is really just a special case of TryFrom, shouldn't it be that From would provide TryFrom, instead of the other way around?

@mqudsi
Copy link
Author

mqudsi commented Sep 8, 2017

@DaseinPhaos Yes, that was a typo. Thanks for catching it - fixed.

@sfackler
Copy link
Member

sfackler commented Sep 8, 2017

That approach isn't really actionable without breaking backwards compatibility.

@mqudsi
Copy link
Author

mqudsi commented Sep 8, 2017

I'm not sure that's necessarily the case, @sfackler .

Step 1) Make sure every struct that implements std::str::FromStr implements either From or TryFrom
Step 2) Remove all manual impls of std::str::FromStr from base
Step 3) Rewrite str::parse() to use TryFrom
Step 4) Warn "FromStr has been deprecated" any time impl std::str::FromStr is called
Step 5) Create a new impl FromStr covering all TryFrom implementors, to be used only by legacy code.

The important thing is that this happens before TryFrom becomes stable, because you can guarantee that no one that has TryFrom also has FromStr (and vice versa), so there will be no conflicting implementations that rust has to resolve. Mark parse() as deprecated while you're at it, and just use into() and try_into() thereafter.

@sfackler
Copy link
Member

sfackler commented Sep 8, 2017

How is step 1 supposed to work? We don't own all Rust code in existence.

@mqudsi
Copy link
Author

mqudsi commented Sep 8, 2017

I think I'm over complicating things. Make sure all current FromStr impls in rust base (not in all rust code everywhere) implement TryFrom<str>. Mark both str::parse() and str::FromStr as deprecated but keep around until whenever we can dump them. Update all documentation and replace parse() with into() and FromStr to TryFrom<str>. Done.

@mqudsi
Copy link
Author

mqudsi commented Nov 5, 2017

Taggging rust-lang/rust#33417

@Centril Centril added the T-libs-api Relevant to the library API team, which will review and decide on the RFC. label Dec 6, 2017
@Kixunil
Copy link

Kixunil commented Apr 25, 2018

An important distinction between impl FromStr for String and (Try)From<String> is that the former must allocate, while the latter is no-op.

If I had been allowed to travel back in time and change something except not adding TryFrom traits, I'd add from_string method with default, overridable implementation to FromStr to do conversions cheaply. :)

Also, I like parse() method because of the name. Rather than deprecating it, I'd prefer resolving this mess via specialization.

@malobre
Copy link

malobre commented Apr 18, 2020

I'm guessing this is blocked until specialization is stabilized ?

Where something like this would be possible:

impl<T> TryFrom<String> for T
where
    T: FromStr,
{
    type Error = <T as FromStr>::Err;

    fn try_from(value: String) -> Result<Self, Self::Error> {
        value.parse()
    }
}

@Kixunil
Copy link

Kixunil commented Apr 18, 2020

@malobre yes, requires specialization. The impl you suggest is still in conflict because String: FromStr, so when T is String you get ambiguity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-libs-api Relevant to the library API team, which will review and decide on the RFC.
Projects
None yet
Development

No branches or pull requests

6 participants