Just a note, I agree with both of you :)
- an enum (or struct)
- its Display implementation
- its Error implementation, now just one function
And a few `impl From<OtherError> for MyError` to make the try? operator work.
For a library it's really not that much work. And even that can be simplified further to a few derive macros with another library : thiserror.
(Sidenote, I don't use `impl Error` because I never use `Box<dyn Error>`. Which isn't to say that's correct, just to say that I've never had the need to implement it)
Using a crate such as thiserror[1] combined with displaydoc[2] makes handling errors in a structured manner a great experience. I love how the error handling story has evolved over the last couple of years in Rust, and it really feels like we're entering into the final stretch of fine-tuning to get the best possible experience.
And yes, anyhow[3] is also great, it serves a different purpose, but I frequently reach for all three crates.
[1]: https://crates.io/crates/thiserror [2]: https://crates.io/crates/displaydoc [3]: https://crates.io/crates/anyhow
What anyhow makes easier is to collect many types of errors together and reporting the errors to the user.