Rust doesn't want to have exceptions; it prefers return value based error handling ("monadic error handling", specifically). A lot of people seem to be under the impression that Rust's error handling model is a way of emulating exceptions -- it's not; it's a different model, and we don't want to emulate exceptions. The fact that error propagation is a common task doesn't mean that Rust's way of providing it is done to emulate exceptions.
------
In a sense, every part of Rust's error handling model is "necessary because Rust doesn't have exceptions". Similarly, every part of Java's error handling model is "necessary because Java makes it hard to do monadic error handling". Saying "X is only necessary because you don't have Y" when X is an alternative to Y isn't a very useful statement.
> something an exception system does for you for free.
That's the point, it doesn't, you pay for the exception system and the implicitness that comes with it. Your comment portrays exceptions as the default that monadic errors are playing catch-up with. I could easily do the reverse.
> is a workaround to make it less of a pain.
You say workaround, I say feature.
Ultimately, monadic errors and exceptions have tradeoffs.
Like I said, given any tradeoff between feature A and feature B, you can always say "subfeature X of A exists because we don't have B". It's not a meaningful thing to say.
I didn't avoid an answer, I genuinely think that your comment has no substance to it because it pretends that exceptions are a "default" system.
I consider "not having exceptions" to be a feature that the ? operator helps to enable. Go also doesn't have exceptions, but they don't have the ? operator, which I find to be a little repetitive while coding. My fingers are outrageously good at:
if err != nil {
return err
}
Comparing Rust to a language with exceptions, like Java, the only difference is that they places that the code can return is explicit rather than implicit, because of that one extra character. I find this extremely pragmatic since most of the time errors just need to be propagated up to a place where they can be handled, but you still need to know when that may happen.
But technically you're doing this wrong, since you should be gift-wrapping your errors in Go. So either you have to be a human exception handler, or god help you should you need to figure out where an error actually occurred.