Here I want to propose my solution, which only need std to expose one macro: std::ok!(), which will expand to Ok(()).
Then we can write functions like this:
fn try_foo() -> Result<(), CustomError> {
// Do some hard stuff
ok!()
}
The great point is that, as ! is used as the macro marker for Rust, it is also used to express a strong feeling in English, and "ok!" sounds like finally, after all hard work, we succeeded with much joy!
If ok() as a function wasn't accepted, I'm pretty sure there's no way ok!() as a macro would be accepted -- generally one should never use a macro when a function would work fine.
I can't remember if we (libs-api) ever considered an ok() function. Some quick skimming of the above links did turn up this, but I'm not sure if it was ever seriously entertained.
At least speaking personally, I don't really think Ok(()) is a problem that ought to be solved. But opinions I think differ wildly about this.
Personally, i do think simply adding the ok() or ok!() for std prelude can just solve the problem. At least for me, the motivation to get rid of Ok(()) is just the weird double parentheses.
I don't see it as a major improvement – it's just superficial syntax. It doesn't even improve type inference or remove need for Ok in methods returning other values.
Having both syntaxes will only cause churn and bikeshedding about which form should be used in codebases.
It being "weird" is just a matter of getting used to it. It's consistent with what () is, and maybe the unit/void should have been a different symbol, but it's too late to change it.
Why does this, among all discussion this forum has, keep coming up?
Typing Ok(()) is 1 character more than the proposed solution. RA autocompletes it. It looks less weird if you've been using Rust for <1 year, and looks the same after that. And even if this was accepted, it would not "kill" Ok(()), there would still be code using the "old" syntax. I for example find Ok(()) to be more expressive of what's happening. And in your own code, you're free to do
I have written Rust for over 5 years, and just as you said, it does look less weird as time goes on. And I do believe that some little change could improve the coding experience a lot, like the newly-added matches! and let-else sentence.
And yes, maybe I should just define and use that simple ok function by myself.
It's fine, don't worry. And don't take it on yourself... I didn't mean to be rude, I just feel like this is such a small change that it isn't worth wasting effort on it. But tastes in syntax differ, I guess.
The more I think about it, the more I feel like my whole generic mutability thing is also just a syntax preference that many don't care about... with possibly little gain. Although a definitely more complex one.
I am a strong proponent of a proper Ok-wrapping in try blocks and try fns. But in my opinion ok!(), ok(), etc. are ad-hoc solutions which only reduce consistency of the language, so I prefer the current status quo over them.
try blocks fully solve the problem of trailing Ok(()), you just don't write anything. They are also strongly desirable for other reasons. Given that, it makes no sense to introduce any kind of ad hoc syntax, regardless whether it's good, bad, long, short. Whatever you propose would be instantly obsolete and deprecated the moment try blocks arrive.
Also note that in your own code it's trivial to define both an ok! macro and an error-polymorphic ok() function. Publish it as a crate if you think it's an issue worth bothering with.
Good to know! Hopefully, as the next logical step try fns will be introduced as well. Personally, I don't care much whether they will look as try fn foo() -> Result<T, E> { ... } or as fn foo() -> Result<T, E> try { ... }. And there is still a name to decide for yeet.
There's a standard problem in language design, where two different desires pull in different directions:
Minimizing the total surface area of the language that people have to know in order to read it. This pulls in the direction of orthogonality: using features X and Y together should work, and work in the obvious way, and you shouldn't need lots of special cases.
Optimizing the language for writing by expert developers. This pulls in the direction of more special cases, more helpers, more specialized language constructs, and so on.
On balance, Rust tends to aim for more orthogonality, ease of reading other people's code, and ease of learning. Ok(()) is easy to understand: it's () wrapped in Ok. It doesn't need "solving".
I think the most likely solution for writing it less will be Ok-wrapped try blocks.