1 % Input to functions and methods
3 ### Let the client decide when to copy and where to place data. [FIXME: needs RFC]
11 // use b as owned, directly
20 // use b as owned after cloning
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`.
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.
37 fn foo(b: Bar) -> Bar { ... }
43 fn foo(b: Box<Bar>) -> Box<Bar> { ... }
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.
50 ### Minimize assumptions about parameters. [FIXME: needs RFC]
52 The fewer assumptions a function makes about its inputs, the more widely usable
55 #### Minimizing assumptions through generics:
60 fn foo<T: Iterator<i32>>(c: T) { ... }
66 fn foo(c: &[i32]) { ... }
67 fn foo(c: &Vec<i32>) { ... }
68 fn foo(c: &SomeOtherCollection<i32>) { ... }
71 if the function only needs to iterate over the data.
73 More generally, consider using generics to pinpoint the assumptions a function
74 needs to make about its arguments.
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.
82 #### Minimizing ownership assumptions:
87 fn foo(b: &Bar) { ... }
88 fn foo(b: &mut Bar) { ... }
94 fn foo(b: Bar) { ... }
97 That is, prefer borrowing arguments rather than transferring ownership, unless
98 ownership is actually needed.
100 ### Prefer compound return types to out-parameters. [FIXME: needs RFC]
105 fn foo() -> (Bar, Bar)
111 fn foo(output: &mut Bar) -> Bar
114 for returning multiple `Bar` values.
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.
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:
124 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>
127 (From the [Read trait](https://doc.rust-lang.org/stable/std/io/trait.Read.html#tymethod.read).)
129 ### Consider validating arguments, statically or dynamically. [FIXME: needs RFC]
131 _Note: this material is closely related to
132 [library-level guarantees](../../safety/lib-guarantees.md)._
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".
138 Instead, Rust code should _enforce_ the validity of input whenever practical.
140 Enforcement can be achieved through the following mechanisms (listed
141 in order of preference).
143 #### Static enforcement:
145 Choose an argument type that rules out bad inputs.
155 fn foo(mode: FooMode) { ... }
161 fn foo(mode2: bool, mode3: bool) {
162 assert!(!mode2 || !mode3);
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.
171 On the other hand, some properties are difficult or impossible to
174 #### Dynamic enforcement:
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
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.
186 #### Dynamic enforcement with `debug_assert!`:
188 Same as dynamic enforcement, but with the possibility of easily turning off
189 expensive checks for production builds.
191 #### Dynamic enforcement with opt-out:
193 Same as dynamic enforcement, but adds sibling functions that opt out of the
196 The convention is to mark these opt-out functions with a suffix like
197 `_unchecked` or by placing them in a `raw` submodule.
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
203 > **[FIXME]** Should opt-out functions be marked `unsafe`?