5 ms·
Author of `wherr` here. > I think the disadvantage you mention is actually an advantage. I would probably want this to propagate alongside other `track_caller`
by JoelJacobson 3y ago
Author of `wherr` here.
> I think the disadvantage you mention is actually an advantage. I would probably want this to propagate alongside other `track_caller`'s since anyone using `track_caller` is "in the know" about where that error should be appearing to come from.
I've now read about `#[track_caller]`, and that's my conclusion too. For those who haven't heard about `#[track_caller]` like myself, I can recommend this page: https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html#track_caller https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html#track...
> TBH I had assumed this crate was using the `#[track_caller]` attribute.
TBH, having read about the `#[track_caller]` attribute, I'm starting to think the crate should use it.
If you and/or @afdbcreid would be interested in working with me on a new implementation of the `wherr` crate that uses the `#[track_caller]` approach instead, please contact me at joel at compiler dot org. Hope to hear from you!
> The main downside I see is that if I manually construct the error type I'll miss that place, unless the constructor of that error also tracks the caller.
You mean, we would need to make sure the error type is always created via a new() constructor method, and that the new() method also has the `#[track_caller]` attribute? Something like this?
impl MyError {
#[track_caller]
pub fn new<E: StdError + Send + Sync + 'static>(error: E) -> Self {
Self {
error: Box::new(error),
location: Location::caller(),
}
}
}
- insanitybit 3y ago> You mean, we would need to make sure the error type is always created via a new() constructor method, and that the new() method also has the `#[track_caller]` attribute? Something like this? Exactly. Although I think because `T: Impl Into<T>` it may not be necessary.
- afdbcreid 3y agoYou're free to use it and/or create a crate for it. If you do, I would go with the second version (the one I linked in the playground), as it is more optimized and allows for not `Send + Sync` and lifetimes other than `'static`. It can be optimized further using unsafe code to use one word (like `anyhow`) does, but I don't think it is necessary. The code I posted is minimal: I would also add `From` impls for not `Send + Sync`, and maybe other features of popular error crates: the two most important that come to mind is downcasting and more importantly, adding a context to an error before propagating it. Downcasting requires unsafe code though, I think. I actually have another nice new idea about contexts, so I may actually publish my own crate... If you don't do that before me. If you do, maybe I'll contribute :)
- JoelJacobson 3y agoI've added a branch for this: https://github.com/joelonsql/wherr/tree/track_caller https://github.com/joelonsql/wherr/tree/track_caller `src/lib.rs` is your code copy/pasted, with the addition of `impl<'a, E: StdError + 'a> From<E> for Box<dyn MyError + 'a>` like suggested (and also just `Send`). I've also added a `fn inner_error<'a>(&'a self) -> &'a (dyn StdError + 'a);`, but not sure this is the proper way. I can't wrap my head around how to match on the inner error though, see `examples/matching_inner.rs`: match my_error_wrapped().unwrap_err() { _ => todo!(), } Can you figure it out?