Skip to content

Commit 1f00ab8

Browse files
committed
add a consideration for must_use
1 parent 8583740 commit 1f00ab8

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
- [Code considerations](./code-considerations/summary.md)
2020
- [Design](./code-considerations/design/summary.md)
2121
- [Public APIs](./code-considerations/design/public-apis.md)
22+
- [When to add `#[must_use]`](./code-considerations/design/must-use.md)
2223
- [Breaking changes](./code-considerations/breaking-changes/summary.md)
2324
- [Breakage from changing behavior](./code-considerations/breaking-changes/behavior.md)
2425
- [Breakage from new trait impls](./code-considerations/breaking-changes/new-trait-impls.md)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# When to add `#[must_use]`
2+
3+
The `#[must_use]` attribute can be applied to types or functions where failing to explicitly consider them or their output is almost certainly a bug.
4+
5+
As an example, `Result` is `#[must_use]` because failing to consider it may indicate a caller didn't realise a method was fallible:
6+
7+
```rust
8+
// If `check_status` returns a `Result`, we might assume this
9+
// call was infallible
10+
check_status();
11+
```
12+
13+
Operators like `saturating_add` are also `#[must_use]` because failing to consider its output might indicate a caller didn't realise they don't mutate the left hand side:
14+
15+
```rust
16+
let a = 42;
17+
let b = 13;
18+
19+
// A caller might assume this method mutates `a`
20+
a.saturating_add(b);
21+
```
22+
23+
Combinators produced by the `Iterator` trait are `#[must_use]` because failing to consider them might indicate a caller didn't realize `Iterator`s are lazy and won't actually do anything unless you drive them:
24+
25+
```rust
26+
// A caller might not realise none of this code won't do anything
27+
// unless they call `collect`, `count`, etc.
28+
slice.iter().filter(|v| v > 10).map(|v| v + 2);
29+
```
30+
31+
On the other hand, `thread::JoinHandle` isn't `#[must_use]` because spawning and forgetting background work is a legitimate pattern and forcing callers to ignore it is less likely to catch bugs:
32+
33+
```rust
34+
thread::spawn(|| {
35+
// this background work isn't waited on
36+
});
37+
```
38+
39+
## For reviewers
40+
41+
The `#[must_use]` attribute only produces warnings, so it can technically be introduced at any time. To avoid accumulating nuisance warnings though ping `@rust-lang/libs` for input before adding new `#[must_use]` attributes to existing types and functions.

0 commit comments

Comments
 (0)