Skip to content

Commit 7bcfe47

Browse files
committed
unify error module docs
1 parent ada65c2 commit 7bcfe47

File tree

3 files changed

+139
-140
lines changed

3 files changed

+139
-140
lines changed

library/core/src/error.md

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
Interfaces for working with Errors.
2+
3+
# Error Handling In Rust
4+
5+
The Rust language provides two complementary systems for constructing /
6+
representing, reporting, propagating, reacting to, and discarding errors.
7+
These responsibilities are collectively known as "error handling." The
8+
components of the first system, the panic runtime and interfaces, are most
9+
commonly used to represent bugs that have been detected in your program. The
10+
components of the second system, `Result`, the error traits, and user
11+
defined types, are used to represent anticipated runtime failure modes of
12+
your program.
13+
14+
## The Panic Interfaces
15+
16+
The following are the primary interfaces of the panic system and the
17+
responsibilities they cover:
18+
19+
* [`panic!`] and [`panic_any`] (Constructing, Propagated automatically)
20+
* [`PanicInfo`] (Reporting)
21+
* [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting)
22+
* [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating)
23+
24+
The following are the primary interfaces of the error system and the
25+
responsibilities they cover:
26+
27+
* [`Result`] (Propagating, Reacting)
28+
* The [`Error`] trait (Reporting)
29+
* User defined types (Constructing / Representing)
30+
* [`match`] and [`downcast`] (Reacting)
31+
* The question mark operator ([`?`]) (Propagating)
32+
* The partially stable [`Try`] traits (Propagating, Constructing)
33+
* [`Termination`] (Reporting)
34+
35+
## Converting Errors into Panics
36+
37+
The panic and error systems are not entirely distinct. Often times errors
38+
that are anticipated runtime failures in an API might instead represent bugs
39+
to a caller. For these situations the standard library provides APIs for
40+
constructing panics with an `Error` as it's source.
41+
42+
* [`Result::unwrap`]
43+
* [`Result::expect`]
44+
45+
These functions are equivalent, they either return the inner value if the
46+
`Result` is `Ok` or panic if the `Result` is `Err` printing the inner error
47+
as the source. The only difference between them is that with `expect` you
48+
provide a panic error message to be printed alongside the source, whereas
49+
`unwrap` has a default message indicating only that you unwraped an `Err`.
50+
51+
Of the two, `expect` is generally preferred since its `msg` field allows you
52+
to convey your intent and assumptions which makes tracking down the source
53+
of a panic easier. `unwrap` on the other hand can still be a good fit in
54+
situations where you can trivially show that a piece of code will never
55+
panic, such as `"127.0.0.1".parse::<std::net::IpAddr>().unwrap()` or early
56+
prototyping.
57+
58+
# Common Message Styles
59+
60+
There are two common styles for how people word `expect` messages. Using
61+
the message to present information to users encountering a panic
62+
("expect as error message") or using the message to present information
63+
to developers debugging the panic ("expect as precondition").
64+
65+
In the former case the expect message is used to describe the error that
66+
has occurred which is considered a bug. Consider the following example:
67+
68+
```should_panic
69+
// Read environment variable, panic if it is not present
70+
let path = std::env::var("IMPORTANT_PATH").unwrap();
71+
```
72+
73+
In the "expect as error message" style we would use expect to describe
74+
that the environment variable was not set when it should have been:
75+
76+
```should_panic
77+
let path = std::env::var("IMPORTANT_PATH")
78+
.expect("env variable `IMPORTANT_PATH` is not set");
79+
```
80+
81+
In the "expect as precondition" style, we would instead describe the
82+
reason we _expect_ the `Result` should be `Ok`. With this style we would
83+
prefer to write:
84+
85+
```should_panic
86+
let path = std::env::var("IMPORTANT_PATH")
87+
.expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`");
88+
```
89+
90+
The "expect as error message" style does not work as well with the
91+
default output of the std panic hooks, and often ends up repeating
92+
information that is already communicated by the source error being
93+
unwrapped:
94+
95+
```text
96+
thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6
97+
```
98+
99+
In this example we end up mentioning that an env variable is not set,
100+
followed by our source message that says the env is not present, the
101+
only additional information we're communicating is the name of the
102+
environment variable being checked.
103+
104+
The "expect as precondition" style instead focuses on source code
105+
readability, making it easier to understand what must have gone wrong in
106+
situations where panics are being used to represent bugs exclusively.
107+
Also, by framing our expect in terms of what "SHOULD" have happened to
108+
prevent the source error, we end up introducing new information that is
109+
independent from our source error.
110+
111+
```text
112+
thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6
113+
```
114+
115+
In this example we are communicating not only the name of the
116+
environment variable that should have been set, but also an explanation
117+
for why it should have been set, and we let the source error display as
118+
a clear contradiction to our expectation.
119+
120+
**Hint**: If you're having trouble remembering how to phrase
121+
expect-as-precondition style error messages remember to focus on the word
122+
"should" as in "env variable should be set by blah" or "the given binary
123+
should be available and executable by the current user".
124+
125+
[`panic_any`]: crate::panic::panic_any
126+
[`PanicInfo`]: crate::panic::PanicInfo
127+
[`catch_unwind`]: crate::panic::catch_unwind
128+
[`resume_unwind`]: crate::panic::resume_unwind
129+
[`downcast`]: crate::error::Error
130+
[`Termination`]: crate::process::Termination
131+
[`Try`]: crate::ops::Try
132+
[panic hook]: crate::panic::set_hook
133+
[`set_hook`]: crate::panic::set_hook
134+
[`take_hook`]: crate::panic::take_hook
135+
[panic-handler]: <https://doc.rust-lang.org/nomicon/panic-handler.html>
136+
[`match`]: ../../std/keyword.match.html
137+
[`?`]: ../../std/result/index.html#the-question-mark-operator-

library/core/src/error.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
//! Interfaces for working with Errors.
2-
// FIXME(yaahc): link to std docs or common docs and try to figure out intradoc issue
1+
#![doc = include_str!("error.md")]
32
#![unstable(feature = "error_in_core", issue = "none")]
43

54
// A note about crates and the facade:

library/std/src/error.rs

+1-138
Original file line numberDiff line numberDiff line change
@@ -1,141 +1,4 @@
1-
//! Interfaces for working with Errors.
2-
//!
3-
//! # Error Handling In Rust
4-
//!
5-
//! The Rust language provides two complementary systems for constructing /
6-
//! representing, reporting, propagating, reacting to, and discarding errors.
7-
//! These responsibilities are collectively known as "error handling." The
8-
//! components of the first system, the panic runtime and interfaces, are most
9-
//! commonly used to represent bugs that have been detected in your program. The
10-
//! components of the second system, `Result`, the error traits, and user
11-
//! defined types, are used to represent anticipated runtime failure modes of
12-
//! your program.
13-
//!
14-
//! ## The Panic Interfaces
15-
//!
16-
//! The following are the primary interfaces of the panic system and the
17-
//! responsibilities they cover:
18-
//!
19-
//! * [`panic!`] and [`panic_any`] (Constructing, Propagated automatically)
20-
//! * [`PanicInfo`] (Reporting)
21-
//! * [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting)
22-
//! * [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating)
23-
//!
24-
//! The following are the primary interfaces of the error system and the
25-
//! responsibilities they cover:
26-
//!
27-
//! * [`Result`] (Propagating, Reacting)
28-
//! * The [`Error`] trait (Reporting)
29-
//! * User defined types (Constructing / Representing)
30-
//! * [`match`] and [`downcast`] (Reacting)
31-
//! * The question mark operator ([`?`]) (Propagating)
32-
//! * The partially stable [`Try`] traits (Propagating, Constructing)
33-
//! * [`Termination`] (Reporting)
34-
//!
35-
//! ## Converting Errors into Panics
36-
//!
37-
//! The panic and error systems are not entirely distinct. Often times errors
38-
//! that are anticipated runtime failures in an API might instead represent bugs
39-
//! to a caller. For these situations the standard library provides APIs for
40-
//! constructing panics with an `Error` as it's source.
41-
//!
42-
//! * [`Result::unwrap`]
43-
//! * [`Result::expect`]
44-
//!
45-
//! These functions are equivalent, they either return the inner value if the
46-
//! `Result` is `Ok` or panic if the `Result` is `Err` printing the inner error
47-
//! as the source. The only difference between them is that with `expect` you
48-
//! provide a panic error message to be printed alongside the source, whereas
49-
//! `unwrap` has a default message indicating only that you unwraped an `Err`.
50-
//!
51-
//! Of the two, `expect` is generally preferred since its `msg` field allows you
52-
//! to convey your intent and assumptions which makes tracking down the source
53-
//! of a panic easier. `unwrap` on the other hand can still be a good fit in
54-
//! situations where you can trivially show that a piece of code will never
55-
//! panic, such as `"127.0.0.1".parse::<std::net::IpAddr>().unwrap()` or early
56-
//! prototyping.
57-
//!
58-
//! # Common Message Styles
59-
//!
60-
//! There are two common styles for how people word `expect` messages. Using
61-
//! the message to present information to users encountering a panic
62-
//! ("expect as error message") or using the message to present information
63-
//! to developers debugging the panic ("expect as precondition").
64-
//!
65-
//! In the former case the expect message is used to describe the error that
66-
//! has occurred which is considered a bug. Consider the following example:
67-
//!
68-
//! ```should_panic
69-
//! // Read environment variable, panic if it is not present
70-
//! let path = std::env::var("IMPORTANT_PATH").unwrap();
71-
//! ```
72-
//!
73-
//! In the "expect as error message" style we would use expect to describe
74-
//! that the environment variable was not set when it should have been:
75-
//!
76-
//! ```should_panic
77-
//! let path = std::env::var("IMPORTANT_PATH")
78-
//! .expect("env variable `IMPORTANT_PATH` is not set");
79-
//! ```
80-
//!
81-
//! In the "expect as precondition" style, we would instead describe the
82-
//! reason we _expect_ the `Result` should be `Ok`. With this style we would
83-
//! prefer to write:
84-
//!
85-
//! ```should_panic
86-
//! let path = std::env::var("IMPORTANT_PATH")
87-
//! .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`");
88-
//! ```
89-
//!
90-
//! The "expect as error message" style does not work as well with the
91-
//! default output of the std panic hooks, and often ends up repeating
92-
//! information that is already communicated by the source error being
93-
//! unwrapped:
94-
//!
95-
//! ```text
96-
//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6
97-
//! ```
98-
//!
99-
//! In this example we end up mentioning that an env variable is not set,
100-
//! followed by our source message that says the env is not present, the
101-
//! only additional information we're communicating is the name of the
102-
//! environment variable being checked.
103-
//!
104-
//! The "expect as precondition" style instead focuses on source code
105-
//! readability, making it easier to understand what must have gone wrong in
106-
//! situations where panics are being used to represent bugs exclusively.
107-
//! Also, by framing our expect in terms of what "SHOULD" have happened to
108-
//! prevent the source error, we end up introducing new information that is
109-
//! independent from our source error.
110-
//!
111-
//! ```text
112-
//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6
113-
//! ```
114-
//!
115-
//! In this example we are communicating not only the name of the
116-
//! environment variable that should have been set, but also an explanation
117-
//! for why it should have been set, and we let the source error display as
118-
//! a clear contradiction to our expectation.
119-
//!
120-
//! **Hint**: If you're having trouble remembering how to phrase
121-
//! expect-as-precondition style error messages remember to focus on the word
122-
//! "should" as in "env variable should be set by blah" or "the given binary
123-
//! should be available and executable by the current user".
124-
//!
125-
//! [`panic_any`]: crate::panic::panic_any
126-
//! [`PanicInfo`]: crate::panic::PanicInfo
127-
//! [`catch_unwind`]: crate::panic::catch_unwind
128-
//! [`resume_unwind`]: crate::panic::resume_unwind
129-
//! [`downcast`]: crate::error::Error
130-
//! [`Termination`]: crate::process::Termination
131-
//! [`Try`]: crate::ops::Try
132-
//! [panic hook]: crate::panic::set_hook
133-
//! [`set_hook`]: crate::panic::set_hook
134-
//! [`take_hook`]: crate::panic::take_hook
135-
//! [panic-handler]: <https://doc.rust-lang.org/nomicon/panic-handler.html>
136-
//! [`match`]: ../../std/keyword.match.html
137-
//! [`?`]: ../../std/result/index.html#the-question-mark-operator-
138-
1+
#![doc = include_str!("../../core/src/error.md")]
1392
#![stable(feature = "rust1", since = "1.0.0")]
1403

1414
// A note about crates and the facade:

0 commit comments

Comments
 (0)