Earlier today, I wanted to make a function in a trait generic over its 'resultness' (i.e., generic over whether it has Result<(), SomeError> or just the unit type () as its Output type). However, when using this function in a context that is generic over the Output type, it should still be possible to short-circuit using the ? operator.
Finally, I opted for defining my own Unit type to enable this and did something akin to:
#![feature(never_type, try_trait_v2)]
use std::ops::{ControlFlow, FromResidual, Try};
struct Unit;
impl FromResidual<!> for Unit {
fn from_residual(_: !) -> Self {
unreachable!()
}
}
impl Try for Unit {
type Output = ();
type Residual = !;
fn branch(self) -> ControlFlow<!> {
ControlFlow::Continue(())
}
fn from_output(_: ()) -> Self {
Self
}
}
trait Foo {
type Output: Try<Output = ()>;
fn foo(&self) -> Self::Output;
}
struct Bar;
impl Foo for Bar {
type Output = Unit;
fn foo(&self) -> Self::Output {
Unit
}
}
struct Baz;
impl Foo for Baz {
type Output = Result<(), String>;
fn foo(&self) -> Self::Output {
Err("Baz".to_string())
}
}
fn run_foo<T: Foo>(foo: T) -> T::Output {
foo.foo()?;
println!("This should only run for Bar but not for Baz");
foo.foo()
}
Obviously, this would be much nicer, if <Bar as Foo>::Output would be () instead of Unit. One way to make that possible would be to put these FromResidual and Try as they are written above for Unit into the standard library for (). However, that would mean that the ? operator suddenly becomes usable on every value of type (), which would obviously not be very desirable. Would there be any other way to make this work in a generic context but not for normal unit values?
Ah, thanks. I have yet to learn all the different locations where discussions about language and standard library design could happen. It’s a bummer that this is not being considered in conjunction with a strong lint.
Of course, I could just do that. However, you still have to call .unwrap() or something on Result<(), Infallible> if you don't want to have warnings like unused `Result` that must be used.
Well, in the generic case, you'd have to unwrap/? anyway so if unused_must_use didn't trigger on Result<T, Infallible>, unless T is itself annotated with #[must_use], that would be a nice improvement already.