It's about ergonomics. The concern is what happens when a junior dev hits some Result<> they don't really know how to deal with. Something like this:
io::stdout().flush().unwrap()
This kind of sucks. The "verb" of this line of code is flush(), and in most languages the verb of a line of code is the last thing on it. It's what people are used to scanning for. .unwrap()s bury it in the middle of the line, which makes code harder to scan for verbs. Additionally, everybody has "unwrap is a code smell" chanted at them by Rust people "in the know".So I want to make this go away, but there isn't a sensible thing for me to do if the universe is fucked to the point where flush isn't working, so matching on the result feels like enormous overkill because I don't really know what to do with the error.
io::stdout().flush()?
Reads a hell of a lot better. It communicates what I'm actually trying to do more simply, and scans a lot better. Of course, it only works in functions that return Result<>s, because it's a Result propagation mechanism, not a do-or-die mechanism.So if I'm a junior programmer, coming from some less strict language, a bit confused about all of this and I want code to read the way I expect it to read coming from other languages, I might start sprinkling in ?s every time I have to deal with these "Result" thingys. Of course, then the compiler yells at me because my caller has to unwrap Results, so I sprinkle in some more ?s and change my return type, and then...etc.
Pretty soon every function in the codebase returns a Result<> just so the code stays more readable and they can punt errors to main and exit, like they're used to.
tl;dr I think we're likely to see junior devs using a lot more Result<>s than they need to, because ? is more readable and "don't use unwrap" is Dogma.
Not sure how well this generalizes to your broader complaint. One could argue that in general, you really do need to think about errors to write good software, so even if languages with exceptions make it slightly easier to write of code that doesn't, that's actually an antifeature because it encourages sloppiness. But maybe that's overly punitive rather than pragmatic. Still, I don't think the answer is exceptions.
[1] preferably because of course other errors are possible, especially if stdout is redirected to a file on disk - but then, in a quick and dirty program, if you ignore errors, you're doing no worse than umpteen million C programs that call printf without checking the return value.
But you could make the case that I'm being overly pessimistic in focusing on the worst case mess that could be made with this feature.
Eg) plenty of people posting code snippets asking for help in the usual places (/r/rust, the forum, SO) will immediately have 5 commentors jump down their throat if there's an unwrap in sight.
Unwrapping may be acceptable in application code - it depends on your application. Specifically it depends on whether you need specific handling of unexpected events.
If your program is a 'script' - by which I mean something that executes for a short period of time to perform a series of tasks and then exits - then panicking on an error is a reasonable way of aborting.
On the other hand, if it's a daemon, then you will likely want to gracefully handle all error conditions and carry on.
I think the issue here is that Rust is primarily used as a systems programming language and usage tends more to fall in the 'daemon' category. In that mentality you handle every error (even if it's just to print something), and that is probably where the general community pointers towards avoiding unwrap come from.
As for exceptions, having them is a non-starter given that Rust intends to be useful in environment where unwinding is simply unavailable. Both Dropbox and Firefox make use of Rust code compiled without any unwinding support. So you can either bifurcate your ecosystem with factions that alternately support errors-as-exceptions and errors-as-return-values, or you can rally around a single one and work to make its usage as nice as you can.