Designing Error Types in Rust Libraries
16 points by skeptrune
16 points by skeptrune
a library consumer will have to depend on
sqlx
andreqwest
crates to use these error variants, even if they never use the database or network functionality directly.
But sqlx
and reqwest
libraries will be compiled in to the binary, so those dependencies are already present. So what’s the fuss? And such a binary is is a database or network/web app at this point anyway.
Semver hazard and ergonomics:
to use this error you need to go and add sqlx to your cargo.toml
That really depends on what you mean by “to use this error”. You need to add sqlx to your cargo.toml if you want to be able to name the wrapped error type, but you can manipulate existing values of the error without naming it.
It is admittedly annoying when a crate exposes an external type in its own API without reexporting that external crate, but for error types the most common operation for an error is simply reporting it to the user or logging system, and that typically doesn’t require actually manipulating the wrapped source error types.
If the sub error has variants you want to match against, it can be a pain to pull in that dependency and guarantee it’s the same version of the subdependency. Otherwise it will error. Rust is happy to pull in different versions of the same crate and complain if you try to mix and match them.
re-exporting these error types
This is one of the biggest pains with the rust crate ecosystem in general. I recently hit an issue with two crates with compatible types that refused to play nice because one was silently “cargo lock”-d to a different sub dependency version https://github.com/rust-lang/cargo/issues/15591.
When I was using rust, the biggest pain around this issue was that you got a bad error message. I remember it said something like types Foo and Foo are incompatible which is mystifying.
The messages have gotten better, but it’s still a bit mystifying how to fix the problems sometimes. There’s not a “force XYZ to unify” and it’s not common that crates reexport their dependencies (as suggested by the article) but I think that re-exports when exposing sub dependency types should be more encouraged.
I was originally mystified that crates.io is reasonably large, but seems to resist people sharing business logic (which is quite common on rubygems.org) or building larger “frameworks” that tie together many common interfaces. I now feel that the difficulty of unifying subdependencies is at least part of what’s preventing (more) of that behavior.