Tracking issue for Result::into_ok
I would like to propose adding a unwrap_infallible associated function to core::result::Result. The purpose is to convert Result<T, core::convert::Infallible> to a T, as the error case is impossible.
The implementation would basically be:
impl<T> Result<T, Infallible> {
#[inline]
pub fn unwrap_infallible(self) -> T {
match self {
Ok(value) => value,
}
}
}
An example use-case I have is a wrapper type with generic value verification, like Handle<T:Verify>. Some verifications can fail, but some can not. When verification is infallible, a Result<Handle<T>, Infallible> will be returned.
Since some can fail, the Handle type implements TryFrom and not From. Because of the blanket implementation of TryFrom for all types implementing From, I can't additionally add a From conversion for the infallible cases. This blanket implementation makes sense, as it allows an API to take a T: TryFrom and handle all possible conversions, even infallible ones.
But for the API consumer it would be beneficial to be able to go from an infallible Result<T, Infallible> to a plain T without having to manually match or use expect. The latter is shorter and chainable, but has the disadvantage that it will still compile when the types are changed and the conversion is no longer infallible.
It might be that there is a different solution to infallible conversions via TryFrom in the future, for example via specialization. I believe that having an unwrap_infallible would still be beneficial in many other cases where generically fallible actions can be infallible in certain situations. One example is when working with a library that is based on fallible operations with a user supplied error type, but where the specific implementation from the user is infallible.
I'd be happy to work on a PR for this if it's acceptable to add, though I might require some guidance with regards to stability attributes, feature flags and so on. It's a bit hard to find information on that, and experimentation is costly as it takes me a while to complete a ./x.py test src/libcore :)
This is (now) a tracking issue for https://doc.rust-lang.org/nightly/std/result/enum.Result.html#method.into_ok https://doc.rust-lang.org/nightly/std/result/enum.Result.html#method.into_err
#![feature(unwrap_infallible)]
I would like to propose adding a
unwrap_infallibleassociated function tocore::result::Result. The purpose is to convertResult<T, core::convert::Infallible>to aT, as the error case is impossible.The implementation would basically be:
impl<T> Result<T, Infallible> { #[inline] pub fn unwrap_infallible(self) -> T { match self { Ok(value) => value, } } }An example use-case I have is a wrapper type with generic value verification, like
Handle<T:Verify>. Some verifications can fail, but some can not. When verification is infallible, aResult<Handle<T>, Infallible>will be returned.Since some can fail, the
Handletype implementsTryFromand notFrom. Because of the blanket implementation ofTryFromfor all types implementingFrom, I can't additionally add aFromconversion for the infallible cases. This blanket implementation makes sense, as it allows an API to take aT: TryFromand handle all possible conversions, even infallible ones.But for the API consumer it would be beneficial to be able to go from an infallible
Result<T, Infallible>to a plainTwithout having to manually match or useexpect. The latter is shorter and chainable, but has the disadvantage that it will still compile when the types are changed and the conversion is no longer infallible.It might be that there is a different solution to infallible conversions via
TryFromin the future, for example via specialization. I believe that having anunwrap_infalliblewould still be beneficial in many other cases where generically fallible actions can be infallible in certain situations. One example is when working with a library that is based on fallible operations with a user supplied error type, but where the specific implementation from the user is infallible.I'd be happy to work on a PR for this if it's acceptable to add, though I might require some guidance with regards to stability attributes, feature flags and so on. It's a bit hard to find information on that, and experimentation is costly as it takes me a while to complete a
./x.py test src/libcore:)scottmcm at 2025-03-04 18:57:59
How is this different from the never (
!) type? In fact, that page mentions Infallible errors with the same wording.Lonami at 2019-06-09 16:39:59
@Lonami I'm not sure I understand the question in relation to the proposal?
core::convert::Infallibleis an existing type that acts as a stand-in for the never type, since the never type itself is still unstable. Core APIs likeTryFromalready useInfallible.I'm proposing an unwrapping
fnonResultthat is specific to dealing withcore::convert::Infallible, and later (when it's stable) the never type.Robert »phaylon« Sedlacek at 2019-06-09 16:49:12
Oh, sorry, I should've checked first, I was unaware of that ^^
Lonami at 2019-06-09 16:50:45
No problem! Should've maybe added some background information,
TryFromandInfallibleare rather recent additions :)Robert »phaylon« Sedlacek at 2019-06-09 17:19:41
Looks like this might be https://github.com/rust-lang/rfcs/issues/1723?
scottmcm at 2019-06-11 04:39:14
@scottmcm Ah, yes. I didn't go back to 2016, and didn't search in the RFCs :)
Robert »phaylon« Sedlacek at 2019-06-11 10:49:28
Hijacking this as a tracking issue for https://github.com/rust-lang/rfcs/pull/2799 I'm amazed at: 1) myself for never finding this before writing the RFC; 2) anyone who has seen my proposal at internals.rust-lang.org not bringing up this issue either.
Mikhail Zabaluev at 2019-11-02 15:13:37
Is there anything else required to begin the process of stabilizing the feature?
Denis at 2020-04-01 02:10:48
into_err(analogous tounwrap_errforResult<!, E>) should also be added, I thinkkotauskas at 2020-08-20 17:00:19
@mexus You can always make a stabilization PR and see what libs thinks 🙃
Unfortunately
!still isn't stable, so it's possible that the current bound ofE: Into<!>might make it impractical to take advantage of on stable. I don't know whether a change to use the usual placeholder (E: Into<core::convert::Infallible>) would be acceptable.scottmcm at 2020-09-25 18:32:03
I published a PR for adding the corresponding
Result::into_err: #83421. I hope we can use the same feature gate and tracking issue?I think the
into_errversion is at least as justified asinto_ok. I'm currently in a very real situation where I'm starting to useResult<Infallible, Error>. But I had to introduce my own trait for now to safely extract theErrorin a non panicking way. I know the typeResult<Infallible, Error>looks a bit strange. I have not studied if there is a reason the enum is calledInfallibleinstead ofNever. But the documentation forInfalliblestates that it carries the same role as!does. And the documentation for!clearly states that a valid use case isResult<!, E>for operations that run indefinitely or until they hit an error.The standard library simply has the return type
-> Errorfor this type of run-until-error operations. But I don't think that's because it's more idiomatic thanResult<!, E>. I think it's just becauseexecwas introduced long beforeInfalliblewas a thing. A downside with-> Erroris that you can't use?inside the function for aborting with the error. I thinkResult<!, E>is more idiomatic and show the intent better.Linus Färnstrand at 2021-03-23 20:42:32
Is there anything blocking this being stabilized? This can already be used without
!being stable thanks to the nice workaround invented inbad::Never:tada:. (All credit to @nvzqz :clap:)If this feature is stabilized. The following would work on stable:
fn infallible_op() -> Result<String, bad::Never> { Ok("hello".into()) } fn main() { let x: String = infallible_op().into_ok(); println!("Great results: {}", x); }Linus Färnstrand at 2021-03-23 21:55:08
I posted PR #83493 in order to implement
impl Into<!> for Infallible. If that PR is not accepted, I think we should change the trait bound oninto_okandinto_errto beInto<Infallible>instead. That's the only way to make these methods usable on stable with the current standard never type stand-in.Linus Färnstrand at 2021-03-25 21:53:19
What about the more general trait bound,
Into<T>? i.e.impl<T, E: Into<T>> Result<T, E> { pub fn into_ok(self) -> T { match self { Ok(x) => x, Err(e) => e.into(), } } } /// and a corresponding `into_err`This could make using stuff like
<[T]>::binary_searcheasier, likeslice.binary_search(&x).into_ok()Cyborus04 at 2021-10-12 03:14:13
@Cyborus04
What about the more general trait bound,
Into<T>?This bound does not generalize
Into<!>, so the current usage and purpose ofinto_ok(which started off asunwrap_infallible) would no longer apply.This could make using stuff like
<[T]>::binary_searcheasier, likeslice.binary_search(&x).into_ok()I feel that this case is too niche to justify adding a special method on
Result.Mikhail Zabaluev at 2021-10-12 08:55:18
This bound does not generalize
Into<!>Oh, right. Can't implement
!: Into<T>cause that would conflict withT: Into<T>. Don't know why I didn't see that.I feel that this case is too niche to justify adding a special method on Result.
Fair enough
Edit: what about
Result::into_ok_or_err(#82223)? That serves the same purpose as what I suggestedCyborus04 at 2021-10-12 12:25:44
What's needed for stabilization of this?
Martin Habovštiak at 2022-02-10 16:44:00
My understanding here is that this was blocked on what to do about
!, which we'd wantinto_okto also work with. https://github.com/rust-lang/rust/pull/83493 was one attempt at getting at that problem, but was closed due to inactivity. Instead of resurrecting that path, I think the faster path is now to wait on!stabilizing, which appears to now be right around the corner. This will also, as far as I can tell, bring:type Infallible = !;which would resolve that concern. Once https://github.com/rust-lang/rust/issues/35121 stabilizes, the path to stabilizing this should, I think, be fairly straightforward and uncontroversial.
Jon Gjengset at 2024-01-17 14:42:25
what to do about
!, which we'd wantinto_okto also work withSince there will be
type Infallible = !, this is non-issue. Until then it works on stable, then it'll continue to work. Except nightly wouldn't supportinto_okwith!until that type alias is available but I don't see how this would be a problem since it's already the case.Martin Habovštiak at 2024-01-17 18:20:54
This issue adds the infallible
into_ok() -> Tandinto_err() -> E. May I suggest one more infallible method?impl<T> Result<T, T> { fn into_inner(self) -> T { let (Ok(r) | Err(r)) = self; r } }Orson Peters at 2024-05-28 21:42:44
I'm not sure I see the usefulness of
into_inner(). What would a use case of such a method be?It also looks like this was already discussed in https://github.com/rust-lang/rust/issues/82223, and ultimately rejected because it's unidiomatic; It incentives using
Resultas anEithertype, which is not the intended use.Olivia Kinnear at 2024-05-28 23:46:06
@superatomic An example where this comes up is when you do a
compare_exchangeand regardless of its outcome you go into the same codepath.I think rejecting it outright as unidiomatic is too presumptuous. If the Rust standard library has interfaces that return
Result<T, T>(it does, see above), it should also support ergonomic methods for dealing with aResult<T, T>.Orson Peters at 2024-05-29 00:19:36
Honestly, I don't have an opinion either way. I think it's a reasonable method to add, especially for use with
compare_exchange. However, I'm not sure it's related tointo_ok()andinto_err(), since it doesn't involve theInfallibletype (in fact, ifTisInfallible, theninto_inner()cannot be called). It just seems to me that the discussion has already been had.Olivia Kinnear at 2024-05-29 00:45:43
Convenience methods for
Result<T, T>are unrelated to convenience methods where one type is!, so I don't think this should be discussed here. This was also extensively discussed and rejected already in https://github.com/rust-lang/rust/issues/82223Linus Färnstrand at 2024-05-29 12:45:01
With Rust 1.82 we got the omitting empty types in pattern matching feature. Is the
unwrap_infalliblemethods (into_ok+into_err) still needed? I was heavily in the camp of adding these methods, but now I'm less sure. With Rust 1.82 you can simply do:fn compute_data_infallible() -> Result<Data, Infallible> {...} fn run_until_error() -> Result<Infallible, Error> {...} fn main() { let Ok(data) = compute_data_infallible(); let Err(error) = run_until_error(); }This does not allow using the computation involving the
Resultdirectly as an expression, theunwrap_infalliblemethods would allow that. But is it important? The places I found where I used workarounds for this, I just assigned the result directly to variables anyway.At the very least, I think the documentation for
into_okandinto_errshould talk about using this new pattern matching to achieve the same thing.Linus Färnstrand at 2024-10-28 08:48:49
Could iterators also have
into_okandinto_errmethods (whenItem = Result<T, !>andItem = Result<!, E>respectively) for converting iterators of results instead of calling.map(|r| r.into_ok())? I have an API I'm working on that could benefit from it (a lot of infallible results).Jonah Henriksson at 2025-03-01 04:39:14
@JonahPlusPlus There would be minimal gain for that. You can write
.map(Result::into_ok)if you'd like to avoid the closure.Jacob Pratt at 2025-03-01 04:50:22
@jhpratt that seems to be also a good argument that the method is still useful.
Martin Habovštiak at 2025-03-04 12:05:48
The
Iteratortrait API surface is already huge. I really don't think we should add methods that only help slightly and only in pretty niche use cases. With slightly I mean that writing.map(Result::into_ok)is very short and neat, why have sugar to make it even shorter?Linus Färnstrand at 2025-03-04 15:10:29
@faern not sure who you're replying to but to be clear I meant
Result::into_okmethod, notIterator::into_ok.Martin Habovštiak at 2025-03-04 15:12:40
Could iterators also have
into_okandinto_errmethods […]The answer this is essentially always "no" for anything that can trivially be written as
.map(…).There's no end of possible methods that people might want to do with this, so really the only practical point on the spectrum of possibilities is to reject all of them.
Not to mention that having more map-like types means re-implementing a bunch of the
Mapoptimizations on those other iterators, which is a ton of maintenance cost for negligible gain.If you do this alot, write a function that returns
impl Iterator<Item = …>.Iteratorwill never have all of these.(Or use something like https://lib.rs/crates/fallible-iterator if you want a trait with a bunch of helpers for iterator-of-results.)
scottmcm at 2025-03-04 18:56:15