[Pre-RFC] `Result::void()` and `Option::void()`

There's no such coercion, though.

I suspect, if it were to exist, I think it'd be pub const OK<T>: Result<(), T> = Ok(());, but that would need some sort of "generic constants", which don't exist yet.

Yup, that was mentioned in the parent. I think there have been proposals for generic constants and statics in the past...

Why not allow such coercions for Result<!, T>, Result<T, !> and Option<!> (and other enums that look just like these, including Result<Result<T, !>, !>)?

Specifically, these variants carry no tag. That means coercing them to the appropriate variant is just a matter of adding a tag, which is about as zero-cost as it gets. We already have coercions from ! to anything else, and there are plenty of cases where those coercions fail with an error, so adding more coercions that can fail with an error is okay.

I agree that making "the last call" different is not nice. For that reason, despite the added verbosity, I actually prefer writing

foo()?;
bar()?;
Ok(())

over

foo()?;
bar()

and (in case there is a value to be returned)

foo()?;
Ok(bar()?)

over

foo()?;
bar()

I think it is best to be able to directly see when a fallible function is called, so all calls to fallible functions should use ?, even the last one. However, having such code in the compiler is hard as sometimes people do "cleanup" and revert it back to the IMO less desirable form (there might be a clippy lint or so, not sure, but I mostly gave up on having the Miri code be in the style that I consider more readable and maintainable).

void() would not really be better than the status quo in my opinion, it would still make the last call different.

What would be better than the status quo is Ok-wrapping, but opinions strongly diverge on that one as was already mentioned in the thread. :wink: try blocks currently have Ok-wrapping (or should I say "success-wrapping"), and I hope that they will be stabilized in that form, and then we can see what (if anything) that means for functions.

7 Likes

For those who just want to avoid the explicit type instantiation in Ok(()) and co., how about free-standing functions?

Example:

#[inline(always)]
pub fn ok<T: Default, E>() -> Result<T, E> {
    Ok(Default::default())
}

#[inline(always)]
pub fn err<T, E: Default>() -> Result<T, E> {
    Err(Default::default())
}

You'd still have to explicitly call the function, but the creation of the instance is implicit. Instead of Ok(()), you'd write ok().

Variations of that have been discussed at least as far back as 2017: https://github.com/rust-lang/rfcs/pull/2107#issuecomment-323521532

TBH, though, I've never really been a fan even though I want to do something about the general problem. By the I'm typing ok(), I kinda feel like I might as well just type Ok(()) -- it's not really materially harder, and is clearer than worrying about Default and needing to mention the function in introductory documentation for error handling.

In this case I'd end up sticking with Ok(()) just to avoid indirection.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.