In theory, I like exceptions. In practice, I hate them. Few languages statically check exception handling - e.g. Java, and even then only partially - leading to stability-ruining edge cases leaking into production in the most unexpected of places caught only by QA if you're lucky. Exception handling codegen can also be rather atrocious, leading to unavoidable performance degredation when third party middleware throws unavoidable exceptions, even when you do fix the stability bugs. They're also a nasty and reoccuring source of undefined behavior when they unwind past a C ABI boundary, an issue I've encountered in multiple codebases with multiple exception-throwing languages. In my personal experience, programmers are also rather terrible at writing exception-safe code.
Result and ? force you to think about - or at least acknowledge - the edge cases. For a throwaway script or small scale easily tested program, that might be a drawback. For MLOC+ codebases where link times alone are sufficient to start impeding testing iteration times, it can be a big help for correctness and stability, while still being relatively lightweight compared to other manual error handling.
Finally - Rust has exceptions. They're called panics. They can be configured to abort instead of unwind. This helps set the tone - they're really meant for bugs, and exceptionally exceptional circumstances. They cause all the problems of exceptions, too - unconsidered edge cases, undefined behavior unwinding past C ABIs, the works. Fortunately, it's reasonable in Rust to aim to eliminate all panics but bugs.
It's very important to minimize the burden of handling errors in code with simple control flow. Frequently I see people try very hard to handle errors with monads in languages like Scala at the micro level and they are so burned out by this that they don't put any effort into handling errors properly at the macro level.
If you make the micro level as automatic as you can it is possible devs will address the macro level, and what is necessary at the micro level is not dealing with a crisis that prevents the compiler from building your code, but rather cleaning up the environment consistently in both normal in error conditions and giving the macro level sufficient context for the error that it can do the right thing.
I've built crash collection and deduplication systems, I've heard of triage that helps discount crashes generated by hardware failures or overeager overclocking. I've collected telemetry and setup symbol servers and source indexing to streamline bug squishing, and helped build systems which verify game content up-front to discover even non-code bugs before they're shipped to users, and to properly attribute said errors to the content that generated said errors in an easily navigatable and fixable way. I've helped engineer error-tollerant systems that won't require handholding by engineering to recover from bugs. Plenty of focus on the macro.
But all it takes is a single uncaught exception slipping past QA to cause one to consider a recall of physical product, even in this era of ubiquitous internet, for a handheld console game for something as trivial as a missing or corrupt sound effect. If things at the micro level are neglected too much, and nothing you do at the macro level can really mitigate that in a sane manner... except use tools that check you're doing things right at the micro level. And I have yet to see exceptions handle that micro level particularly well.
Result and ? force you to think about - or at least acknowledge - the edge cases. For a throwaway script or small scale easily tested program, that might be a drawback. For MLOC+ codebases where link times alone are sufficient to start impeding testing iteration times, it can be a big help for correctness and stability, while still being relatively lightweight compared to other manual error handling.
Finally - Rust has exceptions. They're called panics. They can be configured to abort instead of unwind. This helps set the tone - they're really meant for bugs, and exceptionally exceptional circumstances. They cause all the problems of exceptions, too - unconsidered edge cases, undefined behavior unwinding past C ABIs, the works. Fortunately, it's reasonable in Rust to aim to eliminate all panics but bugs.