about summary refs log tree commit diff
path: root/src/doc/style/features/functions-and-methods/input.md
diff options
context:
space:
mode:
Diffstat (limited to 'src/doc/style/features/functions-and-methods/input.md')
-rw-r--r--src/doc/style/features/functions-and-methods/input.md201
1 files changed, 201 insertions, 0 deletions
diff --git a/src/doc/style/features/functions-and-methods/input.md b/src/doc/style/features/functions-and-methods/input.md
new file mode 100644
index 00000000000..b0912ea0203
--- /dev/null
+++ b/src/doc/style/features/functions-and-methods/input.md
@@ -0,0 +1,201 @@
+% Input to functions and methods
+
+### Let the client decide when to copy and where to place data. [FIXME: needs RFC]
+
+#### Copying:
+
+Prefer
+
+```rust
+fn foo(b: Bar) {
+   // use b as owned, directly
+}
+```
+
+over
+
+```rust
+fn foo(b: &Bar) {
+    let b = b.clone();
+    // use b as owned after cloning
+}
+```
+
+If a function requires ownership of a value of unknown type `T`, but does not
+otherwise need to make copies, the function should take ownership of the
+argument (pass by value `T`) rather than using `.clone()`. That way, the caller
+can decide whether to relinquish ownership or to `clone`.
+
+Similarly, the `Copy` trait bound should only be demanded it when absolutely
+needed, not as a way of signaling that copies should be cheap to make.
+
+#### Placement:
+
+Prefer
+
+```rust
+fn foo(b: Bar) -> Bar { ... }
+```
+
+over
+
+```rust
+fn foo(b: Box<Bar>) -> Box<Bar> { ... }
+```
+
+for concrete types `Bar` (as opposed to trait objects). This way, the caller can
+decide whether to place data on the stack or heap. No overhead is imposed by
+letting the caller determine the placement.
+
+### Minimize assumptions about parameters. [FIXME: needs RFC]
+
+The fewer assumptions a function makes about its inputs, the more widely usable
+it becomes.
+
+#### Minimizing assumptions through generics:
+
+Prefer
+
+```rust
+fn foo<T: Iterator<int>>(c: T) { ... }
+```
+
+over any of
+
+```rust
+fn foo(c: &[int]) { ... }
+fn foo(c: &Vec<int>) { ... }
+fn foo(c: &SomeOtherCollection<int>) { ... }
+```
+
+if the function only needs to iterate over the data.
+
+More generally, consider using generics to pinpoint the assumptions a function
+needs to make about its arguments.
+
+On the other hand, generics can make it more difficult to read and understand a
+function's signature. Aim for "natural" parameter types that a neither overly
+concrete nor overly abstract. See the discussion on
+[traits](../../traits/README.md) for more guidance.
+
+
+#### Minimizing ownership assumptions:
+
+Prefer either of
+
+```rust
+fn foo(b: &Bar) { ... }
+fn foo(b: &mut Bar) { ... }
+```
+
+over
+
+```rust
+fn foo(b: Bar) { ... }
+```
+
+That is, prefer borrowing arguments rather than transferring ownership, unless
+ownership is actually needed.
+
+### Prefer compound return types to out-parameters. [FIXME: needs RFC]
+
+Prefer
+
+```rust
+fn foo() -> (Bar, Bar)
+```
+
+over
+
+```rust
+fn foo(output: &mut Bar) -> Bar
+```
+
+for returning multiple `Bar` values.
+
+Compound return types like tuples and structs are efficiently compiled
+and do not require heap allocation. If a function needs to return
+multiple values, it should do so via one of these types.
+
+The primary exception: sometimes a function is meant to modify data
+that the caller already owns, for example to re-use a buffer:
+
+```rust
+fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>
+```
+
+(From the [Reader trait](http://static.rust-lang.org/doc/master/std/io/trait.Reader.html#tymethod.read).)
+
+### Consider validating arguments, statically or dynamically. [FIXME: needs RFC]
+
+_Note: this material is closely related to
+  [library-level guarantees](../../safety/lib-guarantees.md)._
+
+Rust APIs do _not_ generally follow the
+[robustness principle](http://en.wikipedia.org/wiki/Robustness_principle): "be
+conservative in what you send; be liberal in what you accept".
+
+Instead, Rust code should _enforce_ the validity of input whenever practical.
+
+Enforcement can be achieved through the following mechanisms (listed
+in order of preference).
+
+#### Static enforcement:
+
+Choose an argument type that rules out bad inputs.
+
+For example, prefer
+
+```rust
+fn foo(a: ascii::Ascii) { ... }
+```
+
+over
+
+```rust
+fn foo(a: u8) { ... }
+```
+
+Note that
+[`ascii::Ascii`](http://static.rust-lang.org/doc/master/std/ascii/struct.Ascii.html)
+is a _wrapper_ around `u8` that guarantees the highest bit is zero; see
+[newtype patterns]() for more details on creating typesafe wrappers.
+
+Static enforcement usually comes at little run-time cost: it pushes the
+costs to the boundaries (e.g. when a `u8` is first converted into an
+`Ascii`). It also catches bugs early, during compilation, rather than through
+run-time failures.
+
+On the other hand, some properties are difficult or impossible to
+express using types.
+
+#### Dynamic enforcement:
+
+Validate the input as it is processed (or ahead of time, if necessary).  Dynamic
+checking is often easier to implement than static checking, but has several
+downsides:
+
+1. Runtime overhead (unless checking can be done as part of processing the input).
+2. Delayed detection of bugs.
+3. Introduces failure cases, either via `fail!` or `Result`/`Option` types (see
+   the [error handling guidelines](../../errors/README.md)), which must then be
+   dealt with by client code.
+
+#### Dynamic enforcement with `debug_assert!`:
+
+Same as dynamic enforcement, but with the possibility of easily turning off
+expensive checks for production builds.
+
+#### Dynamic enforcement with opt-out:
+
+Same as dynamic enforcement, but adds sibling functions that opt out of the
+checking.
+
+The convention is to mark these opt-out functions with a suffix like
+`_unchecked` or by placing them in a `raw` submodule.
+
+The unchecked functions can be used judiciously in cases where (1) performance
+dictates avoiding checks and (2) the client is otherwise confident that the
+inputs are valid.
+
+> **[FIXME]** Should opt-out functions be marked `unsafe`?