]> git.lizzy.rs Git - rust.git/blob - src/doc/style/features/functions-and-methods/input.md
Auto merge of #33072 - tbu-:pr_duration_new_overflow, r=alexcrichton
[rust.git] / src / doc / style / features / functions-and-methods / input.md
1 % Input to functions and methods
2
3 ### Let the client decide when to copy and where to place data. [FIXME: needs RFC]
4
5 #### Copying:
6
7 Prefer
8
9 ```rust,ignore
10 fn foo(b: Bar) {
11    // use b as owned, directly
12 }
13 ```
14
15 over
16
17 ```rust,ignore
18 fn foo(b: &Bar) {
19     let b = b.clone();
20     // use b as owned after cloning
21 }
22 ```
23
24 If a function requires ownership of a value of unknown type `T`, but does not
25 otherwise need to make copies, the function should take ownership of the
26 argument (pass by value `T`) rather than using `.clone()`. That way, the caller
27 can decide whether to relinquish ownership or to `clone`.
28
29 Similarly, the `Copy` trait bound should only be demanded it when absolutely
30 needed, not as a way of signaling that copies should be cheap to make.
31
32 #### Placement:
33
34 Prefer
35
36 ```rust,ignore
37 fn foo(b: Bar) -> Bar { ... }
38 ```
39
40 over
41
42 ```rust,ignore
43 fn foo(b: Box<Bar>) -> Box<Bar> { ... }
44 ```
45
46 for concrete types `Bar` (as opposed to trait objects). This way, the caller can
47 decide whether to place data on the stack or heap. No overhead is imposed by
48 letting the caller determine the placement.
49
50 ### Minimize assumptions about parameters. [FIXME: needs RFC]
51
52 The fewer assumptions a function makes about its inputs, the more widely usable
53 it becomes.
54
55 #### Minimizing assumptions through generics:
56
57 Prefer
58
59 ```rust,ignore
60 fn foo<T: Iterator<i32>>(c: T) { ... }
61 ```
62
63 over any of
64
65 ```rust,ignore
66 fn foo(c: &[i32]) { ... }
67 fn foo(c: &Vec<i32>) { ... }
68 fn foo(c: &SomeOtherCollection<i32>) { ... }
69 ```
70
71 if the function only needs to iterate over the data.
72
73 More generally, consider using generics to pinpoint the assumptions a function
74 needs to make about its arguments.
75
76 On the other hand, generics can make it more difficult to read and understand a
77 function's signature. Aim for "natural" parameter types that a neither overly
78 concrete nor overly abstract. See the discussion on
79 [traits](../traits/README.md) for more guidance.
80
81
82 #### Minimizing ownership assumptions:
83
84 Prefer either of
85
86 ```rust,ignore
87 fn foo(b: &Bar) { ... }
88 fn foo(b: &mut Bar) { ... }
89 ```
90
91 over
92
93 ```rust,ignore
94 fn foo(b: Bar) { ... }
95 ```
96
97 That is, prefer borrowing arguments rather than transferring ownership, unless
98 ownership is actually needed.
99
100 ### Prefer compound return types to out-parameters. [FIXME: needs RFC]
101
102 Prefer
103
104 ```rust,ignore
105 fn foo() -> (Bar, Bar)
106 ```
107
108 over
109
110 ```rust,ignore
111 fn foo(output: &mut Bar) -> Bar
112 ```
113
114 for returning multiple `Bar` values.
115
116 Compound return types like tuples and structs are efficiently compiled
117 and do not require heap allocation. If a function needs to return
118 multiple values, it should do so via one of these types.
119
120 The primary exception: sometimes a function is meant to modify data
121 that the caller already owns, for example to re-use a buffer:
122
123 ```rust,ignore
124 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>
125 ```
126
127 (From the [Read trait](https://doc.rust-lang.org/stable/std/io/trait.Read.html#tymethod.read).)
128
129 ### Consider validating arguments, statically or dynamically. [FIXME: needs RFC]
130
131 _Note: this material is closely related to
132   [library-level guarantees](../../safety/lib-guarantees.md)._
133
134 Rust APIs do _not_ generally follow the
135 [robustness principle](https://en.wikipedia.org/wiki/Robustness_principle): "be
136 conservative in what you send; be liberal in what you accept".
137
138 Instead, Rust code should _enforce_ the validity of input whenever practical.
139
140 Enforcement can be achieved through the following mechanisms (listed
141 in order of preference).
142
143 #### Static enforcement:
144
145 Choose an argument type that rules out bad inputs.
146
147 For example, prefer
148
149 ```rust,ignore
150 enum FooMode {
151     Mode1,
152     Mode2,
153     Mode3,
154 }
155 fn foo(mode: FooMode) { ... }
156 ```
157
158 over
159
160 ```rust,ignore
161 fn foo(mode2: bool, mode3: bool) {
162     assert!(!mode2 || !mode3);
163     ...
164 }
165 ```
166
167 Static enforcement usually comes at little run-time cost: it pushes the
168 costs to the boundaries. It also catches bugs early, during compilation,
169 rather than through run-time failures.
170
171 On the other hand, some properties are difficult or impossible to
172 express using types.
173
174 #### Dynamic enforcement:
175
176 Validate the input as it is processed (or ahead of time, if necessary).  Dynamic
177 checking is often easier to implement than static checking, but has several
178 downsides:
179
180 1. Runtime overhead (unless checking can be done as part of processing the input).
181 2. Delayed detection of bugs.
182 3. Introduces failure cases, either via `panic!` or `Result`/`Option` types (see
183    the [error handling guidelines](../../errors/README.md)), which must then be
184    dealt with by client code.
185
186 #### Dynamic enforcement with `debug_assert!`:
187
188 Same as dynamic enforcement, but with the possibility of easily turning off
189 expensive checks for production builds.
190
191 #### Dynamic enforcement with opt-out:
192
193 Same as dynamic enforcement, but adds sibling functions that opt out of the
194 checking.
195
196 The convention is to mark these opt-out functions with a suffix like
197 `_unchecked` or by placing them in a `raw` submodule.
198
199 The unchecked functions can be used judiciously in cases where (1) performance
200 dictates avoiding checks and (2) the client is otherwise confident that the
201 inputs are valid.
202
203 > **[FIXME]** Should opt-out functions be marked `unsafe`?