-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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 methods for unwrapping Result<T, !> / Result<!, E> #1723
Comments
I like |
Another possibility is if |
I believe we could also just use impl<T> From<Result<T, !>> for T {
fn from(r: Result<T, !>) -> T {
r.unwrap()
}
} |
@glaebhoerl What if someone changes the type from |
Well, those are different types so that's a breaking change anyways. |
For the sake of impl<T> From<!> for T {
fn from(r: !) -> T {
match r { }
}
} is my top priority API decision. After that goes whatever else also must also be in stdlib crates to satisfy coherence. |
@Ericson2314 Doesn't that overlap with the identity |
Uh oh. Any ideas? cause that's a crucial impl. |
@Ericson2314 not unless we get some way to say
Well..., if we're doing this in core we can use my favorite unstable hack... (although we really shouldn't ever do this): #![feature(optin_builtin_traits, never_type)]
mod private {
pub trait NotNever {}
impl NotNever for .. {}
impl !NotNever for ! {}
}
trait MyFrom<T> {
fn from(r: T) -> Self;
}
impl<T> MyFrom<T> for T {
fn from(r: T) -> T {
r
}
}
impl<T: private::NotNever> MyFrom<!> for T {
fn from(_: !) -> T {
panic!()
}
} |
@Stebalien that won't work in generic contexts will it? |
@Ericson2314 It seems to work (gist to avoid polluting this thread with nonsense): https://gist.github.com/85c3af06d9db3a31ba810d9a23792350 Unfortunately, it sets a precedent we can't back out of. |
https://is.gd/mU4KWT line 26 fails. I should have been clearer and said I was worried the above wouldn't be as useful due to parametricitiy and a lack of Intriguingly, |
Ah 💩. Good point. (My favorite trick failed me 😿) |
I mean, now that specialization is here, we don't care about parametricity any more, right? :P |
Or maybe there could be a way to explicitly designate an |
@glaebhoerl Sounds like something lattice-based specialization can solve. |
@eddyb hmm? In the case of |
@Ericson2314 Yes, but there are other overlapping cases where the identity impl would change meaning (in the linked example, there would be extra boxing). |
@eddyb sure, just wanted to be clear that that's not strictly relevant for this usecase. |
I think we should still have explicit methods for doing this conversion though and not just rely on IMHO, the only time people should |
To be a bit clearer about what I mean: I think what counts as "completely obvious" depends on who's reading the code. If someone doesn't entirely grok |
@canndrew I think that makes a lot of sense, but I am wondering how to make this more generic... We could just add A couple of ideas I had:
pub trait Always {
type Other; // perhaps a better name?
fn flatten(self) -> Self; // perhaps a better name here too?
}
impl<T> Always<T> for Result<T, !> {
type Other = T;
fn flatten(self) -> Self::Other {
self.ok().unwrap()
}
}
impl<E> Always<E> for Result<!, E> {
type Other = E;
fn flatten(self) -> Self::Other {
self.err().unwrap()
}
} As you can see, this looks very similar to |
Any solution trying to represent the two operations as a single trait will fail to work on |
Trying to abstract the common things between |
@plietar Could you elaborate, please? I don't think I understand @glaebhoerl Hmm... I see what you mean |
@mark-i-m say you have the following implementations, like you suggested :
The are now two implementations of The compiler is actually suprisingly good at describing it : https://is.gd/q9lq04 |
Ah, I see now. Thanks, @plietar |
Has there been any movement in this design space recently? I was helpfully pointed here after proposing an |
I'm not aware of any, but with |
@scottmcm I don't think |
Uh, looks like I reinvented this in #2799 |
One of the main intended uses for the
!
type is to be able construct the typesResult<T, !>
andResult<!, E>
. Right now, if you haver: Result<T, !>
there are several ways to unpack it's innerT
, but none of them are ideal:r.unwrap()
:unwrap
is scary and should be avoided. This is also fragile if someone later changes the error type to something other than!
.r.unwrap_or_else(|e| e)
: Kinda confusing.let Ok(val) = r;
: Requires a separate statement. (Also doesn't currently work).match r { Ok(v) => v, Err(e) => e }
: Both long and kinda confusing.match r { Ok(v) => v }
: Not as nice as a method onr
. (Also doesn't currently work).The void crate adds the methods
void_unwrap
andvoid_unwrap_err
toResult<T, Void>
andResult<Void, T>
. I think methods like these should be added to libcore as well. Perhaps we could call themalways_ok()
andalways_err()
.The text was updated successfully, but these errors were encountered: