-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: error interoperation #201
Conversation
After some discussion on IRC @aturon suggested I link to my efforts on this here. Link: https://github.com/reem/rust-error It is at least partially inspired by some ideas from this RFC, but provides an interface that allows third-party errors the same interface as first-party errors, which a plain enum can't do. I came up with this abstraction while trying to create an abstract error type for Iron, which has rather demanding constraints. |
I didn't have time to do more than a brief skimming of this, and while I'm generally in favor of the motivation of this RFC, I'm worried that this makes |
As a data point, cargo has been using a strategy similar to this for quite some time now, and it's been working out marvelously. |
I'm a huge fan of something like this proposal. Composability of APIs is very important and currently the different error types make for a very hard API. I do not mind losing the ability to have non error things in |
@kballard That's a good point. I actually think the two part of this proposal -- the |
My main issue with this RFC is that this error type does not provide a good way to handle errors. The Error trait makes reporting and propagating errors very nice, but when I receive a I think this is definitely a large step in the right direction, but much more thought needs to be put in to providing a good way to not only safely propagate and mix errors across library boundaries, but to also handle errors across library boundaries. This is a hard problem, but it's one Rust absolutely must solve if we don't want returning |
This looks nice. I like the idea of separating pub trait Error{}
impl<E: Error> FromError<E> for E { ... }
#[deriving(Error)]
struct MyError { ... } BTW: When running the code example in the RFC i seem to get an error http://is.gd/lHcbR2
|
@nielsle This proposal relies on multi-dispatch, which is added in a different RFC. |
@aturon Splitting I feel like the only real solution to this issue is to have two macros, one that is the current |
@kballard Sorry, I think I was unclear. If we decouple the two mechanisms, we can write: impl<E> FromError<E> for E {
fn from_err(err: E) -> E {
err
}
} which, with multidispatch, will still allow you to define other impls when actually converting between error types. This would allow the revised |
Note: I've revised the RFC to decouple |
@aturon Have you considered adding Any-like methods to This kind of functionality is important because there are situations, like in Iron, where you want to express "this should be a generic error handler" but you want that handler to actually be able to handle and introspect errors to a higher degree than just checking their name. |
@reem Yes, in fact I just pushed another update to bound |
Unfortunately, because of the way Any works right now, a bit more effort is needed (at minimum, AnyRefExt needs to be implemented for both |
@reem You're right, my proposal relies on being able to upcast trait objects in general, which is something we intend to be possible but are still working on. Until that lands, we'll probably need a workaround along the lines you're suggesting. I'll revise the RFC accordingly. |
@aturon An additional workaround I've found necessary is to make all the uses of Basically |
I believe that it is planned such that |
6357402
to
e0acdf4
Compare
@alexcrichton Is there an issue I can track for that? |
To me, this seems like a more general argument to remove Is there a specific proposal about this |
@aturon I think this might be related/referring to the fact that Re: previous comment, I had been under the impression that using |
I feel the stack of error messages shouldn't be part of the function signatures if we don't have enough type system to do it right. We could maintain a task-local error queue for example. |
But not for vtable purposes! Which is, of course, the only time you want |
@glaebhoerl Also, that discussion you linked is fascinating. You've basically shown that, as things stand, we can trivially violate parametricity for generics. I will definitely make sure the rest of the team is aware of this. |
@aturon I currently support Iron's error functionality in a library and wouldn't be strongly opposed to continuing to do so with a This could be accomplished downstream with something like: pub struct Lifted<E> where E: Error + Any {
underlying: E
}
pub trait DynamicError: Error + Any {
fn lift<E: Error + Any>(e: E) -> Box<DynamicError> {
box Lifted { underlying: e }
}
}
impl<E> DynamicError for Lifted<E> where E: Error + Any {}
impl Error for Box<DynamicError> { ... } with only one major problem I see: without either If the above was solved, then everything would be fine. |
@reem I'm not sure I understand the worry at the end of your comment. If you The main downside to this over baking in |
Just some food for thought: It would be awesome if this could be the start for making wrapping for results on return implicit. Imagine there was a Old and boring: fn foo(x: bool) -> Result<int, MyError> {
if (x) {
let _ : () = try!(do_something())
}
Ok(42)
} New and fancy: fn foo(x: bool) -> Result<int, MyError> {
if (x) {
try!(do_something())
}
42
} |
@mitsuhiko That is essentially part of #243 in this form:
(I believe this is necessary, as opposed to |
@aturon Ya, with sufficient code duplication I think it's possible to create a general |
This commit brings the `Error` trait in line with the [Error interoperation RFC](rust-lang/rfcs#201) by adding downcasting, which has long been intended. This change means that for any `Error` trait objects that are `'static`, you can downcast to concrete error types. To make this work, it is necessary for `Error` to inherit from `Reflect` (which is currently used to mark concrete types as "permitted for reflection, aka downcasting"). This is a breaking change: it means that impls like ```rust impl<T> Error for MyErrorType<T> { ... } ``` must change to ```rust impl<T: Reflect> Error for MyErrorType<T> { ... } ``` This commit furthermore marks `Reflect` as stable, since we are already essentially committed to it via `Any`. Note that in the future, if we determine that the parametricity aspects of `Reflect` are not needed, we can deprecate the trait and provide a blanket implementation for it for *all* types (rather than by using OIBIT), which would allow all mentions of `Reflect` to be dropped over time. So there is not a strong commitment here. [breaking-change]
This commit brings the `Error` trait in line with the [Error interoperation RFC](rust-lang/rfcs#201) by adding downcasting, which has long been intended. This change means that for any `Error` trait objects that are `'static`, you can downcast to concrete error types. To make this work, it is necessary for `Error` to inherit from `Reflect` (which is currently used to mark concrete types as "permitted for reflection, aka downcasting"). This is a breaking change: it means that impls like ```rust impl<T> Error for MyErrorType<T> { ... } ``` must change to ```rust impl<T: Reflect> Error for MyErrorType<T> { ... } ``` This commit furthermore marks `Reflect` as stable, since we are already essentially committed to it via `Any`. Note that in the future, if we determine that the parametricity aspects of `Reflect` are not needed, we can deprecate the trait and provide a blanket implementation for it for *all* types (rather than by using OIBIT), which would allow all mentions of `Reflect` to be dropped over time. So there is not a strong commitment here. [breaking-change]
This commit brings the `Error` trait in line with the [Error interoperation RFC](rust-lang/rfcs#201) by adding downcasting, which has long been intended. This change means that for any `Error` trait objects that are `'static`, you can downcast to concrete error types. To make this work, it is necessary for `Error` to inherit from `Reflect` (which is currently used to mark concrete types as "permitted for reflection, aka downcasting"). This is a breaking change: it means that impls like ```rust impl<T> Error for MyErrorType<T> { ... } ``` must change to something like ```rust impl<T: Reflect> Error for MyErrorType<T> { ... } ``` except that `Reflect` is currently unstable (and should remain so for the time being). For now, code can instead bound by `Any`: ```rust impl<T: Any> Error for MyErrorType<T> { ... } ``` which *is* stable and has `Reflect` as a super trait. The downside is that this imposes a `'static` constraint, but that only constrains *when* `Error` is implemented -- it does not actually constrain the types that can implement `Error`. [breaking-change]
This commit brings the `Error` trait in line with the [Error interoperation RFC](rust-lang/rfcs#201) by adding downcasting, which has long been intended. This change means that for any `Error` trait objects that are `'static`, you can downcast to concrete error types. To make this work, it is necessary for `Error` to inherit from `Reflect` (which is currently used to mark concrete types as "permitted for reflection, aka downcasting"). This is a breaking change: it means that impls like ```rust impl<T> Error for MyErrorType<T> { ... } ``` must change to something like ```rust impl<T: Reflect> Error for MyErrorType<T> { ... } ``` except that `Reflect` is currently unstable (and should remain so for the time being). For now, code can instead bound by `Any`: ```rust impl<T: Any> Error for MyErrorType<T> { ... } ``` which *is* stable and has `Reflect` as a super trait. The downside is that this imposes a `'static` constraint, but that only constrains *when* `Error` is implemented -- it does not actually constrain the types that can implement `Error`. [breaking-change]
This commit brings the `Error` trait in line with the [Error interoperation RFC](rust-lang/rfcs#201) by adding downcasting, which has long been intended. This change means that for any `Error` trait objects that are `'static`, you can downcast to concrete error types. To make this work, it is necessary for `Error` to inherit from `Reflect` (which is currently used to mark concrete types as "permitted for reflection, aka downcasting"). This is a breaking change: it means that impls like ```rust impl<T> Error for MyErrorType<T> { ... } ``` must change to something like ```rust impl<T: Reflect> Error for MyErrorType<T> { ... } ``` except that `Reflect` is currently unstable (and should remain so for the time being). For now, code can instead bound by `Any`: ```rust impl<T: Any> Error for MyErrorType<T> { ... } ``` which *is* stable and has `Reflect` as a super trait. The downside is that this imposes a `'static` constraint, but that only constrains *when* `Error` is implemented -- it does not actually constrain the types that can implement `Error`. [breaking-change]
This commit brings the `Error` trait in line with the [Error interoperation RFC](rust-lang/rfcs#201) by adding downcasting, which has long been intended. This change means that for any `Error` trait objects that are `'static`, you can downcast to concrete error types. To make this work, it is necessary for `Error` to inherit from `Reflect` (which is currently used to mark concrete types as "permitted for reflection, aka downcasting"). This is a breaking change: it means that impls like ```rust impl<T> Error for MyErrorType<T> { ... } ``` must change to something like ```rust impl<T: Reflect> Error for MyErrorType<T> { ... } ``` except that `Reflect` is currently unstable (and should remain so for the time being). For now, code can instead bound by `Any`: ```rust impl<T: Any> Error for MyErrorType<T> { ... } ``` which *is* stable and has `Reflect` as a super trait. The downside is that this imposes a `'static` constraint, but that only constrains *when* `Error` is implemented -- it does not actually constrain the types that can implement `Error`. [breaking-change]
This commit brings the `Error` trait in line with the [Error interoperation RFC](rust-lang/rfcs#201) by adding downcasting, which has long been intended. This change means that for any `Error` trait objects that are `'static`, you can downcast to concrete error types. To make this work, it is necessary for `Error` to inherit from `Reflect` (which is currently used to mark concrete types as "permitted for reflection, aka downcasting"). This is a breaking change: it means that impls like ```rust impl<T> Error for MyErrorType<T> { ... } ``` must change to ```rust impl<T: Reflect> Error for MyErrorType<T> { ... } ``` This commit furthermore marks `Reflect` as stable, since we are already essentially committed to it via `Any`. Note that in the future, if we determine that the parametricity aspects of `Reflect` are not needed, we can deprecate the trait and provide a blanket implementation for it for *all* types (rather than by using OIBIT), which would allow all mentions of `Reflect` to be dropped over time. So there is not a strong commitment here. [breaking-change] r? @alexcrichton
This commit brings the `Error` trait in line with the [Error interoperation RFC](rust-lang/rfcs#201) by adding downcasting, which has long been intended. This change means that for any `Error` trait objects that are `'static`, you can downcast to concrete error types. To make this work, it is necessary for `Error` to inherit from `Reflect` (which is currently used to mark concrete types as "permitted for reflection, aka downcasting"). This is a breaking change: it means that impls like ```rust impl<T> Error for MyErrorType<T> { ... } ``` must change to something like ```rust impl<T: Reflect> Error for MyErrorType<T> { ... } ``` except that `Reflect` is currently unstable (and should remain so for the time being). For now, code can instead bound by `Any`: ```rust impl<T: Any> Error for MyErrorType<T> { ... } ``` which *is* stable and has `Reflect` as a super trait. The downside is that this imposes a `'static` constraint, but that only constrains *when* `Error` is implemented -- it does not actually constrain the types that can implement `Error`. [breaking-change] Conflicts: src/libcore/marker.rs
fix some copy/paste errors in docs
Update 0000-template.md
This RFC improves interoperation between APIs with different error
types. It proposes to:
try!
macro for clients of multiplelibraries with disparate error types.
by introducing an
Error
trait.The proposed changes are all library changes; no language changes are
needed -- except that this proposal depends on
multidispatch happening.
Rendered