> But, since good programs don’t panic, and neither do good programmers, it’s very rare that using unwrap or expect is actually the right thing to do.<p>I respectfully disagree.<p>The assert!() macro is a way to document invariants. It's a bug if a variant is violated. It shouldn't have happened, but if it happens, then there's nothing the user can do except reporting the crash.<p>The unwrap() and expect() method document the invariant that the None and Err() variants shouldn't occur.<p>It's fail fast.<p>You should use error handling only if users would be able to handle the errors.<p>Tell the end user that the file they wanted to open is not readable, for example. Tell the users of your library that an error happened, like a parse error of a config file. And so on. Tell the users what they can fix themselves.<p>A bug in your library or program, that's something different. Fail fast! And Rust panics are perfect for that.
Maybe not perfect, but it seems to work out better than exceptions. Exceptions are a good idea which turned out to be too complicated.<p>A language has to use destructors to clean up for almost everything for this to work. "?" has no "catch" clause within the function. So if an object has an invariant, and that invariant must be restored on error, the destructors must restore the invariant. If that just means unlocking locks, closing files, or deleting data structures, that works. If some more complex invariant needs to be restored, "?" isn't enough. The calling function has to clean things up. This usually means encapsulating the function that does the work in a function that handles errors and cleanup. Basically, a try block.
Except for anything more production quality, one needs to lean on third party crates to compose errors without explicitly write tons of boilerplate composing result types.<p>Something that should be supported directly.
For those who want to experiment with this style in C#, I've found this package to work: <a href="https://github.com/JohannesMoersch/Functional">https://github.com/JohannesMoersch/Functional</a>
Isn't it based on ML family? I mean, I see Rust error handling heavy inspired in monads used in languages like OCaml and Haskell.<p>Is Rust doing something different?
It's far from perfect.<p>One of the biggest problems with Rust error handling is that if you want to have explicit error return types encoded in the type system you need to create ad hoc enums for each method that returns an error. If you only use a single error type for all functions you will inevitably have functions returning Results that contain error variants that the function will never actually return but still need to be handled.<p>Without enum variants being explicit types and the ability to easily create anonymous enums using union and intersection operators Rust enums require a ton of boilerplate.