37 ms·
> Why expose it I read "expose" in two possible ways: (1) as a public- / user-facing API (2) existing at all. When an error type is a public API that is bound
by shepmaster 3y ago
> Why expose it
I read "expose" in two possible ways: (1) as a public- / user-facing API (2) existing at all.
When an error type is a public API that is bound by semver, I do think you should be very careful about what you expose. I suggest starting with an opaque [1] error type and only exposing exactly what you are comfortable with supporting. That may boil down to basically only a string (a.k.a. the `Error` trait).
> Why expose it as a programmatically-accessible information at all?
A few things come to mind...
I'm a huge fan in testing my error cases as much as possible. To that end, a bunch of my tests are semantically `assert_matches!(Err(MyError::Case { .. }), function_result_value)`.
Not all errors are equivalent. For example, if my library fails to read a configuration file, perhaps the caller of the library can recover from that by downloading a file. However, this requires the caller to be able to tell what caused the error.
Interacting with an external API, such as HTTP status or command line exit codes. In this case, you can categorize your errors into domains like "server error" / "client error" / "authorization error".
These could all be done by string matching, but that tends to be comparatively brittle.
> the same information in a string
Aggregating strings like that requires dynamic allocation, which isn't universally available in Rust programs. For example, SNAFU works fine in a `no_std` environment and I know that it's been used in cases like embedded and Windows kernel drivers.
> if the only purpose is for a developer to read it
I don't think that's always true.
[1]: https://docs.rs/snafu/latest/snafu/guide/opaque/index.html https://docs.rs/snafu/latest/snafu/guide/opaque/index.html