Not the person you're asking, but result types pessimize code more, add register pressure, use more icache for largely dead code, etc. They're arguably noisier at the source level too.
That said, I've spent too much of my life chasing implicit control flow to accept exceptions. Heck, C++'s "noexcept" is a strong argument against exceptions all by itself.
My view is that Java's checked exceptions failed in big part because Java didn't have type variables back then; after all, polymorphic Result types are not that much different from checked exceptions.
I haven't written any Java since it has gained those, so I suspect there might be other aspects making it awkward. And it still would lack exhaustiveness checking that e.g. Rust has.
Checked exceptions were actually the "right way" to do exceptions (if there is such a thing), the problem was just that developers hated them, but I think that draws the wrong conclusion. That tells me their syntax/usage was seen as too much forced boiler plate making code unwieldy, not that they didn't have benefits for correctness (something often not appreciated until years later).
Unchecked exceptions lead to unhandled exceptions at runtime. We've all seen screens with Java programs running with tons of exceptions in the log, or worse, that crash with unhandled exceptions. This is the result of the unchecked exceptions mess, which is why I won't use languages that use them for routine error handling for anything more than trivial programs.
> developers hated them, but I think that draws the wrong conclusion
Exception handling is just annoying from a syntax perspective. Also checked Exceptions have the problem that they bubble up types that a different layer shouldn’t even be aware of due to exception chaining (cause of a cause etc), unless you carefully re-throw them, which nobody did.
Lower ceremony errors are just better to deal with.
C++ noexcept exists because the way C++ evolved, it is no argument against exceptions.
Exceptions came to be during the 1990's, as the C++ARM to C++98 standardisation process was taking place.
Naturally during the early days C++ compilers lacked exceptions, as CFront was introduced without them.
Then we had the C folks that were migrating to C++.
When C++ compilers finally supported exception, compilers vendors introduced the non standard switch to disable them, so that existing code could still compile with the expected behaviour.
The standard itself does not acknowledge this as allowed.
This feature was naturally misused by the anti-exception folks, same applies to how RTTI came to be.
So noexcept is a way to be able to write code to appease both camps, while surfacing what variant was chosen by the programmer.
From my point of view allowing disabling exceptions in first place was a mistake, those folks should have moved back to C, or fixed their code.
You need instructions to check the result type, and a bit somewhere to store whether it's valid. Most exceptions only add extra instructions during throws/unwinding. There may or may not be an overall reduction in code size, depending on how many checks you have vs table entries.
The worst part about rust not having exceptions is that it actually does have exceptions, you just shouldn't use them. All the downsides and none of the benefits:
No, Rust does not have exceptions. Rust has unwinding, if you choose to compile your program with support for it, which you are free not to, and is trivially achieved by a single flag.
It's hard for me to think of a definition of "exception" which doesn't include Rust's panics:
use std::panic::catch_unwind;
fn throws_exception(){
panic!("hello");
}
fn main(){
match catch_unwind(|| {
throws_exception();
println!("Never reached");
}) {
Ok(_) => (),
Err(e) => println!(
"threw an exception: {:?}",
e.downcast_ref::<&'static str>().unwrap())
}
}
I can disable exceptions in rustc, but I can't disable the influence they have on language and library design (as detailed in the link I posted). Exceptions are the main reason you can't temporarily move something out from behind an exclusive reference, or return an error code from a Drop impl. Heck, Rust wouldn't even need destructors if it weren't for exceptions: the compiler could just tell you when you forgot to free something.
No, panics are not exceptions. Exceptions are a mechanism for resumable error-handling. Rust's `catch_unwind` function is a last-ditch mechanism for failure isolation (motivated by preventing UB via unwinding across FFI boundaries), not a general-purpose error recovery mechanism. I have seen many Rust programs in my day, and not a single one has ever used `catch_unwind` in the way that (say) Java or Python programmers use try/catch for error handling, so this is as true in practice as it is in theory.
> I can disable exceptions in rustc, but I can't disable the influence they have on language and library design
It's the other way around. The fact that unwinding can be (and regularly is) trivially disabled is the ultimate motivator of why panics fundamentally cannot be used for error handling, and this is what influences language and library design (ultimately demanding `Result`-based error handling).
> Exceptions are the main reason you can't temporarily move something out from behind an exclusive reference, or return an error code from a Drop impl
No, this is absolutely untrue, and I'm not sure why you think this.
> Heck, Rust wouldn't even need destructors if it weren't for exceptions: the compiler could just tell you when you forgot to free something.
No, this is also untrue, and you appear to misunderstand the purpose of destructors. Feel free to provide code if you would like to try to make a more precise argument against unwinding.
That said, I've spent too much of my life chasing implicit control flow to accept exceptions. Heck, C++'s "noexcept" is a strong argument against exceptions all by itself.