-
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 Reform and Failure Box #492
Conversation
solution to this problem is to box the error up and move it to the heap. While | ||
heap allocation can sound controversial, the truth is that an `IoResult<u8>` is | ||
currently 72 bytes large. Given that the vast majority of IO calls will actually | ||
succeed this is a huge overhead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd still like to see some concrete examples showing that there is in fact "huge overhead" here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, i'm going to provide a proper benchmark for this. The main problem is making it representative :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet in the RFC because I need to validate those numbers, but I get this currently:
test bench_large_result_3 ... bench: 134 ns/iter (+/- 37)
test bench_large_result_7 ... bench: 205 ns/iter (+/- 128)
test bench_large_result_ok_3 ... bench: 14 ns/iter (+/- 8)
test bench_large_result_ok_7 ... bench: 26 ns/iter (+/- 27)
test bench_small_result_3 ... bench: 128 ns/iter (+/- 38)
test bench_small_result_7 ... bench: 134 ns/iter (+/- 41)
test bench_small_result_ok_3 ... bench: 8 ns/iter (+/- 4)
test bench_small_result_ok_7 ... bench: 13 ns/iter (+/- 12)
_N
means that it went through N
stack frames. large_result
means that it's thrown without boxing, small_result
is the same error in a Box
. _ok
means Ok
branch taken, otherwise it's the Err
branch. The error thrown is a regular IoError
.
Code is in the rust-incidents
repo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Came here to ask for exactly these numbers. What is still needed to validate your benchmarks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, this is for IoError
sized structs. The odd thing is that I even see performance improvements on the OK branch for boxed up plain enums which seems suspicious.
|
||
# Questions | ||
|
||
Q: Why is `name()` and `description()` necessary? What about translations? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/is/are/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, fixed.
cc @aturon |
cc @glaebhoerl |
+1, with this RFC I would feel comfortable using Rust's normal error handling in many more scenarios than I currently do (because of size concerns and lack traceback). |
Thanks for bringing up the fat results issue for discussion. |
|
||
```rust | ||
trait ConstructFailure<A> { | ||
fn construct_failure(args: A, loc: Option<LocationInfo>) -> Self; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this lead to unneccesary allocation? Perhaps loc
could be a closure that returned an Option<LocationInfo>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ideal case is loc bring a uint that holds the instruction pointer and getting debug info from dwarf. There is nothing that prevents this other than that it's more work :)
Could you open an issue for the missing null pointer optimisation? |
@arielb1 filed as rust-lang/rust#19419. |
cc rust-lang/rust#18629, a PR about conventions with the values returned by these error methods. |
@mitsuhiko Sorry for the delay in getting back to you on this -- just back from the Mozilla work week in Portland. Thanks for writing up such a detailed and clear RFC! At a high level, I really like this proposal. It's highly practical, and increases the ergonomics of debugging without undue burden elsewhere. So mostly, I just have quibbles/questions about the details.
Is anyone using cc @wycats |
I started out with trying to understand the errors as they are reported currently. At present I miss the name the most because it's tricky to find out which exact error was actually raised. As the description is more free form text content and can differ greatly between errors. The idea was that the error could be rendered like this: "{name}: {description) ({detail})". The difference between name and description is that the name is not a sentence or phrase. The difference between description and detail is that the detail is computed on the fly whereas description is just a basic textual description of what the problem might be. It's also important to point out that currently very often description is the same as detail which makes generic error rendering read really weird.
There are two problems with this. The first is that because at that point you cannot have tracebacks any more or each error needs to be able to store traceback and location information. The second problem is that I could not make generic interoperability between boxed and unboxed errors work while using generic implementations for
You are right that the same issue applies to With failure it feels like there are two concepts: errors and a failure type that wraps an error. With However core problem is still that location information cannot be achieved with Box.
I would say it depends on the API. I would argue that the IoError currently is just too large and it really should be a simple enum. IO operations would just generally return a simple enum that implements
Yes, that in a way would have been the plan. However because of the few different conversions it can provide I figured exposing it for documentation purposes is not the worst idea.
I agree that
The problem with
The traceback pretty much depends on it. Note that the API can be entirely internally for a start.
I agree with this. I would love to get some feedback on if it would be possible to a similar user experience differently.
That's why I would like to split the rfc into two parts; the necessary changes to Error and then everything else. Once the
Because the traits are different using incidents currently is basically too much work :( |
I just tried this out in Cargo (we have a done of
I'll note that in Cargo we rely on being able to send errors across threads (just as a data point). Our use case is that the worker threads (aka parallel builds) are the ones generating errors which need to be communicated back to the main thread.
I may have missed something, but doesn't
As another data point, Cargo is using its own |
@mitsuhiko actually I'm a little confused about one aspect here. In the RFC you've defined the trait Error: 'static + Send + Clone { ... } But one your comments seems to contradict this:
I think @aturon misconstrued the addition of I just wanted to clarify what the intended outcome of the bounds on |
You are absolutely correct. I'm not sure why I missed that :-/
As mentioned I'm not sure about the intended trait bounds. The RFC is the conservative approach I think. I will do some experiments with just
Yeah. Just to clarify the intentions of the bounds:
|
Cool, thanks for the clarification @mitsuhiko! |
@mitsuhiko Just an update: we do plan to take some action here but are currently swamped with other issues getting ready for the alpha. I will be in touch ASAP. |
@mitsuhiko I just had a thought: I wonder whether the new One issue in the original design was whether So perhaps |
@aturon If As I see it, the expectation is that Maybe the |
@mzabaluev Apologies, I didn't see your comment until just now. To be clear, what I meant was that we could use what is now |
@mitsuhiko I'm wondering your thoughts on the change to use I would like to tease out any remaining backwards-incompatible aspects of this RFC; we are getting ready to stabilize Once we've extracted the backcompat hazards, I think this should probably be closed in favor of a You mentioned splitting up the RFC into those two parts previously; are you still open to doing that? I'd like to make some progress here. |
Since this RFC was opened, the For now I'm going to close this RFC, but thanks regardless for it @mitsuhiko! |
This RFC proposes four things:
Error
trait to support better messages.Failure<T>
wrapper for errors to support optional tracebacks.ConstructFailure
trait to support interoperability between errors and failures.try!
andfail!
macros that useConstructFailure
instead ofFromError
.Rendered View