Open phaylon opened 5 years ago
How is this different from the never (!
) type? In fact, that page mentions Infallible errors with the same wording.
@Lonami I'm not sure I understand the question in relation to the proposal?
core::convert::Infallible
is an existing type that acts as a stand-in for the never type, since the never type itself is still unstable. Core APIs like TryFrom
already use Infallible
.
I'm proposing an unwrapping fn
on Result
that is specific to dealing with core::convert::Infallible
, and later (when it's stable) the never type.
Oh, sorry, I should've checked first, I was unaware of that ^^
No problem! Should've maybe added some background information, TryFrom
and Infallible
are rather recent additions :)
Looks like this might be https://github.com/rust-lang/rfcs/issues/1723?
@scottmcm Ah, yes. I didn't go back to 2016, and didn't search in the RFCs :)
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.
Is there anything else required to begin the process of stabilizing the feature?
into_err
(analogous to unwrap_err
for Result<!, E>
) should also be added, I think
@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 of E: 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.
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_err
version is at least as justified as into_ok
. I'm currently in a very real situation where I'm starting to use Result<Infallible, Error>
. But I had to introduce my own trait for now to safely extract the Error
in a non panicking way. I know the type Result<Infallible, Error>
looks a bit strange. I have not studied if there is a reason the enum is called Infallible
instead of Never
. But the documentation for Infallible
states that it carries the same role as !
does. And the documentation for !
clearly states that a valid use case is Result<!, E>
for operations that run indefinitely or until they hit an error.
The standard library simply has the return type -> Error
for this type of run-until-error operations. But I don't think that's because it's more idiomatic than Result<!, E>
. I think it's just because exec
was introduced long before Infallible
was a thing. A downside with -> Error
is that you can't use ?
inside the function for aborting with the error. I think Result<!, E>
is more idiomatic and show the intent better.
Is there anything blocking this being stabilized? This can already be used without !
being stable thanks to the nice workaround invented in bad::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);
}
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 on into_ok
and into_err
to be Into<Infallible>
instead. That's the only way to make these methods usable on stable with the current standard never type stand-in.
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_search
easier, like slice.binary_search(&x).into_ok()
@Cyborus04
What about the more general trait bound,
Into<T>
?
This bound does not generalize Into<!>
, so the current usage and purpose of into_ok
(which started off as unwrap_infallible
) would no longer apply.
This could make using stuff like
<[T]>::binary_search
easier, likeslice.binary_search(&x).into_ok()
I feel that this case is too niche to justify adding a special method on Result
.
This bound does not generalize
Into<!>
Oh, right. Can't implement !: Into<T>
cause that would conflict with T: 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 suggested
What's needed for stabilization of this?
My understanding here is that this was blocked on what to do about !
, which we'd want into_ok
to 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.
what to do about
!
, which we'd wantinto_ok
to also work with
Since 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 support into_ok
with !
until that type alias is available but I don't see how this would be a problem since it's already the case.
This issue adds the infallible into_ok() -> T
and into_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
}
}
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 Result
as an Either
type, which is not the intended use.
@superatomic An example where this comes up is when you do a compare_exchange
and 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 a Result<T, T>
.
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 to into_ok()
and into_err()
, since it doesn't involve the Infallible
type (in fact, if T
is Infallible
, then into_inner()
cannot be called). It just seems to me that the discussion has already been had.
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/82223
With Rust 1.82 we got the omitting empty types in pattern matching feature. Is the unwrap_infallible
methods (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 Result
directly as an expression, the unwrap_infallible
methods 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_ok
and into_err
should talk about using this new pattern matching to achieve the same thing.
I would like to propose adding a
unwrap_infallible
associated 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:
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
Handle
type implementsTryFrom
and notFrom
. Because of the blanket implementation ofTryFrom
for all types implementingFrom
, I can't additionally add aFrom
conversion for the infallible cases. This blanket implementation makes sense, as it allows an API to take aT: 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 plainT
without 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
TryFrom
in the future, for example via specialization. I believe that having anunwrap_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
:)