More than you've ever wanted to know about errors in Rust (2022)
shuttle.rs
shuttle.rs
The title “more than you’ve ever wanted to know about errors in Rust” had me expecting to learn something new.
Still a nice intro though, and could for example form part of the documentation for shuttle in the future, to help people who are new to Rust get into using shuttle.
I would have liked a small conclusion under the chapter that names thiserror, anyhow and eyre, arguing why you might pick one library over another, and which one to pick if you don't have any requirements (anyhow). This blog post compares the two first with examples on when they're neat and cumbersome:
https://www.shakacode.com/blog/thiserror-anyhow-or-how-i-han...
You definitely can: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html
In the context of the article, this is a somewhat minor point. Because you can't guarantee the recovery from panics, you often code as if you can never recover from panics. And thus, when you write code that can panic (for example, `slice[i]`), it's best to conservatively assume that any such panic won't be recovered from. Still though, the existence of a recovery mechanism can be useful advice in some circumstances: https://docs.rs/regex/1.*/regex/#panics
The broader story here is a knot that is difficult to untangle because 1) people have different values and 2) words mean different things to different people. I tried to untangle some part of it here (although it's more broad than just "panics can or can't be recovered from," it's still all connected): https://blog.burntsushi.net/unwrap/
They can control that panic isn't compiled as abort, but even then, if there's a destructor that can panic, then if it panics during unwinding, it aborts. So even the app developer cannot guarantee to catch all panics.
std::result::Result<T, E>
does not restrict E: std::error:Err
Whereas the article doesn't say that this is the case, but it mentioned it in a way that confused me: https://www.shuttle.rs/blog/2022/06/30/error-handling#:~:tex....I'll let someone else clarify the reasoning because I'm not confident I remember it correctly. I though this was in the Rust API guidelines but I can't find it after a quick skin.
there is a nice discussion on this issue here: https://github.com/rust-lang/rust-clippy/issues/1689
Panic is a way for Rust library ecosystem to signal this error in un-recoverable, and is probably a bug in program, for which you would be happy getting Sentry or some such reporting.
Most errors in Rust are handled using mechanisms described in post using Result. Some, this is probably a bug in code, mechanism should be present in other languages.
There are even efforts to make code that can panic detectable at compile time, https://docs.rs/no-panic/latest/no_panic/
Panics are recoverable.
There's a good bunch of programs that are just supposed to read some inputs, perform a task and crash with an error message and exit code if anything goes wrong.
Recoverable errors -> Result/Option, i.e. have your types not lie and say "this function open_file() returns either Ok(file) or Err"
Unrecoverable errors -> panic, i.e. crash your program and present a stack trace for debugging
When they're actionable I prefer actual types.
It's not important in that it doesn't change what the programmer can do with it, it just changes the syntax used.
Return an error: return Err(...) vs. throw ...
Propagate error to caller: ? vs. nothing
Store/modify/nest/pass: Without try/catch/throw construct vs. WITH try/catch/throw construct.
The much more important difference is between bounded vs. unbounded error types. Rust falls in the former camp and inherits all the problems (and benefits) that come with it.
Places where people use precise concrete error types are not forced by the language, it's just the best practice for libraries.