]> git.proxmox.com Git - rustc.git/blame - src/doc/style/errors/signaling.md
New upstream version 1.12.1+dfsg1
[rustc.git] / src / doc / style / errors / signaling.md
CommitLineData
85aaf69f
SL
1% Signaling errors [RFC #236]
2
3> The guidelines below were approved by [RFC #236](https://github.com/rust-lang/rfcs/pull/236).
4
5Errors fall into one of three categories:
6
7* Catastrophic errors, e.g. out-of-memory.
8* Contract violations, e.g. wrong input encoding, index out of bounds.
9* Obstructions, e.g. file not found, parse error.
10
11The basic principle of the convention is that:
12
13* Catastrophic errors and programming errors (bugs) can and should only be
bd371182 14recovered at a *coarse grain*, i.e. a thread boundary.
85aaf69f
SL
15* Obstructions preventing an operation should be reported at a maximally *fine
16grain* -- to the immediate invoker of the operation.
17
18## Catastrophic errors
19
bd371182 20An error is _catastrophic_ if there is no meaningful way for the current thread to
85aaf69f
SL
21continue after the error occurs.
22
23Catastrophic errors are _extremely_ rare, especially outside of `libstd`.
24
25**Canonical examples**: out of memory, stack overflow.
26
27### For catastrophic errors, panic
28
29For errors like stack overflow, Rust currently aborts the process, but
30could in principle panic, which (in the best case) would allow
bd371182 31reporting and recovery from a supervisory thread.
85aaf69f
SL
32
33## Contract violations
34
35An API may define a contract that goes beyond the type checking enforced by the
36compiler. For example, slices support an indexing operation, with the contract
37that the supplied index must be in bounds.
38
39Contracts can be complex and involve more than a single function invocation. For
40example, the `RefCell` type requires that `borrow_mut` not be called until all
41existing borrows have been relinquished.
42
43### For contract violations, panic
44
45A contract violation is always a bug, and for bugs we follow the Erlang
46philosophy of "let it crash": we assume that software *will* have bugs, and we
bd371182 47design coarse-grained thread boundaries to report, and perhaps recover, from these
85aaf69f
SL
48bugs.
49
50### Contract design
51
52One subtle aspect of these guidelines is that the contract for a function is
53chosen by an API designer -- and so the designer also determines what counts as
54a violation.
55
56This RFC does not attempt to give hard-and-fast rules for designing
57contracts. However, here are some rough guidelines:
58
59* Prefer expressing contracts through static types whenever possible.
60
61* It *must* be possible to write code that uses the API without violating the
62 contract.
63
64* Contracts are most justified when violations are *inarguably* bugs -- but this
65 is surprisingly rare.
66
67* Consider whether the API client could benefit from the contract-checking
68 logic. The checks may be expensive. Or there may be useful programming
69 patterns where the client does not want to check inputs before hand, but would
70 rather attempt the operation and then find out whether the inputs were invalid.
71
72* When a contract violation is the *only* kind of error a function may encounter
73 -- i.e., there are no obstructions to its success other than "bad" inputs --
74 using `Result` or `Option` instead is especially warranted. Clients can then use
75 `unwrap` to assert that they have passed valid input, or re-use the error
76 checking done by the API for their own purposes.
77
78* When in doubt, use loose contracts and instead return a `Result` or `Option`.
79
80## Obstructions
81
82An operation is *obstructed* if it cannot be completed for some reason, even
83though the operation's contract has been satisfied. Obstructed operations may
84have (documented!) side effects -- they are not required to roll back after
85encountering an obstruction. However, they should leave the data structures in
86a "coherent" state (satisfying their invariants, continuing to guarantee safety,
87etc.).
88
89Obstructions may involve external conditions (e.g., I/O), or they may involve
90aspects of the input that are not covered by the contract.
91
92**Canonical examples**: file not found, parse error.
93
94### For obstructions, use `Result`
95
96The
e9174d1e 97[`Result<T,E>` type](https://doc.rust-lang.org/stable/std/result/index.html)
85aaf69f
SL
98represents either a success (yielding `T`) or failure (yielding `E`). By
99returning a `Result`, a function allows its clients to discover and react to
100obstructions in a fine-grained way.
101
102#### What about `Option`?
103
104The `Option` type should not be used for "obstructed" operations; it
105should only be used when a `None` return value could be considered a
106"successful" execution of the operation.
107
108This is of course a somewhat subjective question, but a good litmus
109test is: would a reasonable client ever ignore the result? The
110`Result` type provides a lint that ensures the result is actually
111inspected, while `Option` does not, and this difference of behavior
112can help when deciding between the two types.
113
114Another litmus test: can the operation be understood as asking a
115question (possibly with sideeffects)? Operations like `pop` on a
116vector can be viewed as asking for the contents of the first element,
117with the side effect of removing it if it exists -- with an `Option`
118return value.
119
120## Do not provide both `Result` and `panic!` variants.
121
122An API should not provide both `Result`-producing and `panic`king versions of an
123operation. It should provide just the `Result` version, allowing clients to use
124`try!` or `unwrap` instead as needed. This is part of the general pattern of
125cutting down on redundant variants by instead using method chaining.