I've closely followed the RFC and the discussion around Provider API and I have found little information about the drawbacks of the approach (apart from the possible overlap with
Any): I failed to find any rational of why the functionality is needed in the first place and what are the design drawbacks of adding it.
Coming from .Net ecosystem I perceive generic access to errors' inner data as a hacky way to emulate typed exception handling, which, at least as far as I can tell from my .Net experience, is often utilized to quickly handle non-erroneous scenarios by error handling facilities, namely, route the results of not-actually-an-error calls somewhere. Even the typed exception handling makes code more difficult to reason about given the more complex control flow, but "Provider API" gives the ability to pass around arbitrary data completely hidden (on the type level) and, with interior mutability, potentially allowing any logic to be called from anywhere in the callstack.
Are there any discussions/articles/documents on how the "Provider API" is assumed to be utilized and how it potentially affects the complexity?
I believe the primary motivation is to simultaneously have
without also demanding that the
Backtrace type itself is in
More broadly, the same type of situation can arise when:
crate_two depend on
- you have information of type
crate_one::Something which needs to be fetched by
- through a shared non-generic mechanism provided by
Ideally, the common mechanism would be generic, so that
crate_one can declare its provision in a statically verifiable fashion, but in practice that is often infeasible — and I would say, not because of deficiencies in Rust, but because every static type system eventually runs into expressiveness limits. In the case of
Error, the root problem is that
Error::source() returns a
&dyn Error, so it needs to be possible to get the additional information out of a
dyn Error. The provider mechanism allows extension of something otherwise inextensible.
To give a more specific case of the the broader situation, there's a type
SpanTrace which is basically a backtrace but made of tracing-spans instead of function frames, there are crates like
color-eyre that integrate support for capturing and printing these spantraces along with backtraces. Even if
std::error::Error were to integrate backtrace support so that error chains can check if any of the causes provide a backtrace, it won't integrate spantrace support so there's no way to inspect the spantrace from the innermost error where it would have the most context.
Note that sometimes what the callee considers an error, the caller can actually recover from and would like to inspect and handle separately. Being able to "split hairs" like this is useful (e.g., a "cannot find command" is probably not fixable, but "5xx status code" is possibly worth a retry with backoff).
Thank you. I understand. But I'm more interested to learn about the possible risks of the current solution.
As I see it, implementing multiple v-tables and allowing passing
Box<dyn Error + MyContext + ImportantContext + HasSpanTrace + HasDumpAttached> is much more clean, explicit and easier to reason about. What frightens me is the ability to pass hidden possibly mutable state around via error chains.
There's nowhere to attach those extra traits to, you have to fit everything through a
dyn Error shaped hole to support
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.