-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
deriving Error #92
Comments
Thought a bit more about this and I think the best names for the different attributes are as follows: // Error specific from derive that creates a backtrace if there's a field named backtrace
#[from(error)]
// Cancels error specific derive and does a normal from derive for this variant
#[from(noerror)]
// Doesn't derive from for this variant (already implemented)
#[from(ignore)]
// Indicate the specific field that is the source
#[error(source)]
// Indicate that this variant has no source
#[error(nosource)]
// Indicate the backtrace field
#[error(backtrace)]
// Indicate that this variant has no backtrace field
#[error(nobacktrace)]
// Indicate the backtrace field These attributes are only used to change the default behaviour. The default behaviour should be:
Feel free to only implement the |
@JelteF I mostly agree with your design, but have some additions which I will illustrate as a serie of examples (so can be used for tests lately). One of the main points for me: being clever about generics. This is why I use SourcesDefault rules are the same as you've described:
#[derive(Error)]
enum Tuples<A, B, C> {
Anna(A),
Boris(#[error(source)] B, u8),
Calvin(#[error(not(source))] C)
}
// Expanded:
impl<A, B, C> Error for Tuples<A, B, C>
where A: Error,
B: Error,
{
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
Self::Anna(ref x) => Some(x as &(dyn Error + 'static)),
Self::Boris(ref x, _) => Some(x as &(dyn Error + 'static)),
_ => None,
}
}
} #[derive(Error)]
enum Structs<A, B, C, D> {
Anna {
source: A,
},
Boris {
#[error(source)]
boris: B,
num: u8,
}
Calvin {
#[error(not(source))]
source: C,
}
David {
david: D,
}
}
// Expanded:
impl<A, B, C, D> Error for Structs<A, B, C, D>
where A: Error,
B: Error,
{
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
Self::Anna { source: ref x } => Some(x as &(dyn Error + 'static)),
Self::Boris { boris: ref x, .. } => Some(x as &(dyn Error + 'static)),
_ => None,
}
}
} BacktracesWhile for So, default rules are the following:
#[derive(Error)]
enum Tuples {
Anna(Backtrace),
Boris(u8, Backtrace),
Calvin(Backtrace, #[error(backtrace)] Backtrace),
David(String, #[error(not(backtrace))] Backtrace),
Erik(#[error(source)] AnotherError, Backtrace),
Farkas(#[error(source)] AnotherError, #[error(backtrace)] Backtrace),
Vilkas(#[error(source, not(backtrace))] AnotherError, Backtrace),
}
impl Error for Tuples {
fn backtrace(&self) -> Option<&Backtrace> {
match *self {
Self::Anna(ref b) => Some(b),
Self::Boris(_, ref b) => Some(b),
Self::Calvin(_, ref b) => Some(b),
Self::Erik(ref e, _) => e.backtrace(),
Self::Farkas(_, ref b) => Some(b),
Self::Vilkas(_, ref b) => Some(b),
_ => None,
}
}
} #[derive(Error)]
enum Structs {
Anna {
backtrace: Backtrace,
},
Boris {
num: u8,
bt: Backtrace,
},
Calvin {
foo: Backtrace,
#[error(backtrace)]
bar: MyBacktrace, // type alias
},
David {
name: String,
#[error(not(backtrace))]
sup: Backtrace,
},
Erik {
source: AnotherError,
bt: Backtrace,
},
Farkas {
#[error(source)]
err: AnotherError,
#[error(backtrace)]
bt: Backtrace,
},
Vilkas {
#[error(source, not(backtrace))]
err: AnotherError,
bt: Backtrace,
},
}
impl Error for Structs {
fn backtrace(&self) -> Option<&Backtrace> {
match *self {
Self::Anna{ backtrace: ref b } => Some(b),
Self::Boris{ bt: ref b, .. } => Some(b),
Self::Calvin{ bar: ref b, .. } => Some(b),
Self::Erik { source: ref e, .. } => e.backtrace(),
Self::Farkas{ bt: ref b, .. } => Some(b),
Self::Vilkas{ bt: ref b, .. } => Some(b),
_ => None,
}
}
} Why
|
Thanks for the suggestions:
One thing I would slightly change are these defaults for backtrace
I think they would be better like this:
I think this is better, because now you can add a backtrace to an error that doesn't have one by simply adding a This will especially work well once we implement |
Yeah, I thought about this as well, and came to a conclusion that the case were user has its own
I'm quite unsure about it. My point was in preferring longer backtraces as described here, which, again, from my point of view, represents majority of cases. In my experience you rarely attach Btw... at this point the design for |
I think you're making a good point, but the PR for that issue has the best default solution I think:
|
@tyranron do you still plan on working on this? Otherwise I might spend some time on implementing this (once I've finished updating docs). |
Sounds awesome! @ffuugoo please make use of the You would have to add the attributes required for error here: https://github.com/JelteF/derive_more/blob/HEAD@%7B2019-11-02T19:06:15Z%7D/src/utils.rs#L655-L661 |
My current implementation is rather complicated, but I've looked into |
@JelteF I've started working on backtrace support for derive-Error macro and I've encountered a problem with the way you process attributes. So, in This pose an instant problem for derive-Error. Consider: #[derive(Debug, derive_more::Display, derive_more::Error)]
struct MyError(#[error(source)] MyOtherError, std::backtrace::Backtrace); Specifying I did not yet dig too deep on this, but it seems, that the way So, what should I do? I, probably, can figure how to fix it myself, but if you can give some guidance off top of your head, that would be nice. Also, should I open separate PR for this fix, or just include it into "derive-Error Backtrace support" PR? (Notifying @tyranron on the issue as well.) |
For allowing a more ergonomic use and better integration on the ecosystem, this adds the `std::error::Error` `impl` for our custom errors. We intent to drop this hand made code once `derive_more` finishes the addition of the Error derive support[1]. Until that is available, we need to live with that. 1. JelteF/derive_more#92 Signed-off-by: Otavio Salvador <[email protected]>
For allowing a more ergonomic use and better integration on the ecosystem, this adds the `std::error::Error` `impl` for our custom errors. We intent to drop this hand made code once `derive_more` finishes the addition of the Error derive support[1]. Until that is available, we need to live with that. 1. JelteF/derive_more#92 Signed-off-by: Otavio Salvador <[email protected]>
Closing this now, since it has been merged. |
@tyranron I thought some more about your idea for deriving only
Error
withderive(Error)
in #25 and I think it's a great idea. I also saw the new thiserror crate coming by on reddit, which has some cool ideas. I put some ideas on how to add those to derive_more here: dtolnay/thiserror#2 (comment). I asked the author if he wanted to work together on this, but it seems he isn't a fan of that (which is completele fine ofcourse). Please let me know what you think of this syntax and if you're indeed going to pick it up.For completeness here is the content of my comment with ideas (the rest of the issue thread is also useful for context):
The text was updated successfully, but these errors were encountered: