Skip to content

Commit f1c1c5d

Browse files
authored
Merge pull request #9 from rust-lang/must-use
Add a consideration for must_use
2 parents d78363e + f76be08 commit f1c1c5d

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-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: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# When to add `#[must_use]`
2+
3+
The `#[must_use]` attribute can be applied to types or functions when 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+
// Is `check_status` infallible? Or did we forget to look at its `Result`?
9+
check_status();
10+
```
11+
12+
Operators like `saturating_add` are also `#[must_use]` because failing to consider their output might indicate a caller didn't realise they don't mutate the left-hand-side:
13+
14+
```rust
15+
// A caller might assume this method mutates `a`
16+
a.saturating_add(b);
17+
```
18+
19+
Combinators produced by the `Iterator` trait are `#[must_use]` because failing to use them might indicate a caller didn't realize `Iterator`s are lazy and won't actually do anything unless you drive them:
20+
21+
```rust
22+
// A caller might not realise this code won't do anything
23+
// unless they call `collect`, `count`, etc.
24+
v.iter().map(|x| println!("{}", x));
25+
```
26+
27+
On the other hand, `thread::JoinHandle` isn't `#[must_use]` because spawning fire-and-forget work is a legitimate pattern and forcing callers to explicitly ignore handles could be a nuisance rather than an indication of a bug:
28+
29+
```rust
30+
thread::spawn(|| {
31+
// this background work isn't waited on
32+
});
33+
```
34+
35+
## For reviewers
36+
37+
Look for any legitimate use-cases where `#[must_use]` will cause callers to explicitly ignore values. If these are common then `#[must_use]` probably isn't appropriate.
38+
39+
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)