I doesn't seem to make sense to warn here.
Is there a way around that?
I doesn't seem to make sense to warn here.
Is there a way around that?
unwrap()
it. By definition it won't panic.
If you're nervous about the error type changing in the future and biting you, you can also destructure it with a match. The Err
arm shouldn't be required because the enum is empty.
That's not the point. This is returned from a public API, eg futures::SinkExt::send
, on a Sink that is infallible. Given this is infallible, it would be nicer if users could write:
obj.send( something ).await;
// instead of (which is better than unwrap btw)
//
let _ = obj.send( something ).await;
without getting a nonsensical warning. Maybe the lint should just be changed.
You should match Infallible
:
fn handle(r: Result<String, std::convert::Infallible>) -> String {
match r {
Ok(it) => it,
Err(it) => match it {},
}
}
If the Ok value is a tuple, why would you do such a thing?
To verify, at compile time, that the err case is impossible.
I'm sorry, but I don't understand. std::convert::Infallible
is a type that can't be constructed. So the type system already guarantees that an Err
variant will never exist. The Ok value is a tuple, so contains no useful data. The method would just return a tuple if it wasn't a trait impl.
I feel that warning for an unused result in this case is wrong.
A Result is a Result. There's nothing about the must_use
lint that can selectively trigger based on what types the Result is parameterized over. And while a Result<(), Infalliable>
happens to have the same number of inhabitants as a plain ()
, those are still different types with different semantics.
I personally use .unwrap_or_else(|x| match x {})
. It's like the suggested .unwrap()
, but checked at compile time
The longer option would be to have:
trait VoidType {
fn unreachable (self: &'_ Self)
-> !
;
}
impl VoidType for ::core::convert::Infallible {
fn unreachable (self: &'_ Self)
-> !
{
match *self {}
}
}
impl<T, E> ResultExt for Result<T, E> {
type T = T;
type E = E;
}
trait ResultExt {
type T;
type E;
fn unwrap_noop (self: Self)
-> Self::T
where
Self::E : VoidType,
{
self.unwrap_or_else(|err| err.unreachable())
}
}
Using a helper function:
fn ex_falso_quodlibet<T>(x: Infallible) -> T {
match x {}
}
fn handle(r: Result<String, Infallible>) -> String {
r.unwrap_or_else(ex_falso_quodlibet)
}
Note that .unwrap()
not just never panic, it doesn't holds any flag to determine if its failed so branching on it is not even possible.
I have made a crate that does this: Unwrap Infallible Results With All Convenience And No Fear
There is no separate trait to implement for infallible types and a blanket extension impl for Result
as in @Yandros's design. I don't expect there to be many custom never-types that are not just reexports of std::convert::Infallible
. But I have added a feature-gated blanket impl for Result<T, E> where E: From<!>
. This could be morphed into an inherent generic method of standard Result
, if From<!>
becomes a conventional impl to tag types with never occurring values.
This very very much the wrong bound. Every type will impl From<!>
.
What you want is !: From<E>
enum Void {}
impl From<Void> for ! {
fn from(x: Void) -> ! {
match x {}
}
}
but it still doesn't mean much as inhabited type can still impl
it using panic
struct Foo;
impl From<Foo> for ! {
fn form(x: Foo) -> ! {
panic!()
}
}
I see two options:
use a if let
fn main() {
if let Ok(v) = function_that_returns_a_result() {
dbg!(v);
}
}
There is the exhaustive_patterns
feature (which works obviously only on nightly)
#![feature(exhaustive_patterns)]
fn main() {
let Ok(v) = function_that_returns_a_result();
dbg!(v);
}
You are right, I got it the other way around.
This "issue" is not specific to this case: you can make an arbitrary type impl
many traits by having the methods diverge rather than return. That's "just" the implementor's fault. If it just loop
s indefinitely or abort
s the process then there is no memory unsafety (if it panics and unwinds the stack, however, then it could lead to memory unsafety, provided someone used unsafe
in an unsound manner, which is not the case here).
But yes, the guarantee that a unreachable() -> !
method can help get zero-cost unwrapping is only true with cooperative implementations; otherwise it may behave as a classic .unwrap()
.
Another example: the whole Future
s architecture is based on implementors not blocking when polled, which cannot be verified, and thus requires trusting the implementations (cooperative concurrency).
I think I got it covered:
#[cfg(feature = "blanket_impl")]
impl<T, E: Into<!>> UnwrapInfallible for Result<T, E> {
type Ok = T;
fn unwrap_infallible(self) -> T {
match self {
Ok(v) => v,
Err(e) => e.into(),
}
}
}
Curiously, there is no impl From<Infallible> for !
yet. But this could wait until !
is stabilized and Infallible
becomes a type alias for !
.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.