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