Workaround for lack of default generic function type parameter

This is an ergonomics question, above all.

Consider this code:

fn test<R, F, Err>(func: F) -> Result<R, Err>
where F: FnOnce() -> Result<R, Err>
{
    func()
}

fn main() {
    let result = test(|| Ok("yes")).unwrap();
    println!("{result}");
}

It won't work unless I turn this:
test(|| Ok("yes"))
into this:
test(||->Result<&str, ()> { Ok("yes") })

How can this be made nicer to use?

  • I don't want to give up a generic error type, because it's needed in a minority of cases
  • But the majority of cases will never use the error at all and shouldn't have to specify it

Defaults are illegal in function generics... For some reason(s) that even some doyens of early Rust don't seem to know... but the feature to bring them back seems like it died. :cry:

So is there a clever idea I'm not seeing?

Thanks for any thoughts.

You can use Ok::<_, !>("yes"), once the ! type stabilizes. In the mean time, Ok::<_, Infallible>("yes") works too.

If it's a minority of cases, make the Result version try_test, where test calls try_test(|| Ok::<_, Infallible>(f())), wrapping the non-result closure into a result closure.

3 Likes

Thanks. That's definitely an improvement over putting the type in the closure signature.

I still wish Rust had support for more pervasive defaults for generics. For all the reasons in the Tracking Issue for RFC 213: Default Type Parameter Fallback · Issue #27336 · rust-lang/rust · GitHub thread.