Brian MaherWhen I first started writing Rust code, I went through several iterations of error handling. From...
When I first started writing Rust code, I went through several iterations of error handling. From that experience, I have these learnings:
Result<R, E> type for general purpose error handling. Note that "stack frames" will be lost in this error handling unless you do something about it.panic!() (or that family of error handling) for asserting preconditions in your code or really any error that could only happen if the program was incorrect. The beauty of a panic is the you will get a backtrace if the RUST_BACKTRACE environment variable is set.Result<R, E>, as that can easily be converted into a panic!() by the caller.The next natural question is what type to use as the E parameter of Result<R, E>.
When designing any error type, I consider these things:
'static errors is difficult and should be avoided.A that only triggers an error when calling function B, it is convenient to "pass the buck" and simply use ? to propagate the exact same error. However, before blindly doing this ask yourself if there is critical contextual information which may be lost. For example, if you are calling function B on every element of a collection, you may want to add contextual information about which element that error originated from. In this example, you may want to .map_err() to a new error type that attaches the relevant contextual information.panic!() instead.In order to make it easier to create my error types thiserror is enormously valuable in reducing the boilerplate code.