You can also use enums, as shown in the post. You don't need trait objects.
EDIT 1
> without needing to use boxed trait objects [...] `anyhow`
It's my understanding that anyhow uses trait objects. The first sentence of its document says "This library provides anyhow::Error, a trait object based error type"
EDIT 1 END
> which have nice downcasting API
I'm not a fan of downcasting when not _absolutely_ necessary.
See my sibling comment about SNAFU for an alternate that allows keeping different errors separate while unifying them.
I’ve done both in production projects and they both have their merits but 9 out of 10 times I’ll start with `anyhow` if I’m writing library code and then refactor to enums later if I need it instead of the other way around.
EDIT: That said Snafu does look really cool for the cases where you do have a codified sum type of all possible errors.
DOUBLE EDIT: I already had Snafu starred on GH lol
Like everything, it can be a balancing act. I tend to be free about creating error types (one per module, usually, but it's not strange for me to create more). When you implement `std::error::Error` (to be able to make error trait objects) and have a tool like SNAFU (to make error enums), then having more error types isn't much of a hindrance in my experience.
> I’ll start with `anyhow` if I’m writing library code and then refactor to enums later
The newest (beta) version of SNAFU actually strives to make this case even smoother. There's a `whatever!` macro that you can use to create stringly-typed errors and then migrate case-by-case to an enum. Check out the docs for some example usage.
That’s just… wildly annoying to deal with IMO.
1: https://github.com/dtolnay/anyhow
2: https://github.com/yaahc/eyre