Skip to content

Commit

Permalink
get over bold text madness, changes per PR, brought the "returning po…
Browse files Browse the repository at this point in the history
…inters" section back to pointers guide
  • Loading branch information
alan-andrade committed May 24, 2014
1 parent 64dad2c commit 9974465
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 26 deletions.
30 changes: 14 additions & 16 deletions src/doc/guide-lifetimes.md
Expand Up @@ -45,12 +45,11 @@ let on_the_heap : Box<Point> = box Point {x: 7.0, y: 9.0};

Suppose we wanted to write a procedure that computed the distance between any
two points, no matter where they were stored. One option is to define a function
that takes two arguments of type `Point`—that is, it takes the points __by value__.
But if we define it this way, calling the function will cause the points __to be
copied__. For points, this is probably not so bad, but often copies are
expensive. Worse, if the data type contains mutable fields, copying can change
the semantics of your program in unexpected ways. So we'd like to define
a function that takes the points just as a __reference__/__borrowed pointer__.
that takes two arguments of type `Point`—that is, it takes the points by value.
But if we define it this way, calling the function will cause the points to be
copied. For points, this is probably not so bad, but often copies are
expensive. So we'd like to define a function that takes the points just as
a reference.

~~~
# struct Point {x: f64, y: f64}
Expand All @@ -62,27 +61,26 @@ fn compute_distance(p1: &Point, p2: &Point) -> f64 {
}
~~~

Now we can call `compute_distance()`
Now we can call `compute_distance()`:

~~~
# struct Point {x: f64, y: f64}
# let on_the_stack : Point = Point{x: 3.0, y: 4.0};
# let on_the_heap : Box<Point> = box Point{x: 7.0, y: 9.0};
# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
compute_distance(&on_the_stack, on_the_heap);
compute_distance(&on_the_stack, &*on_the_heap);
~~~

Here, the `&` operator takes the address of the variable
`on_the_stack`; this is because `on_the_stack` has the type `Point`
(that is, a struct value) and we have to take its address to get a
value. We also call this _borrowing_ the local variable
`on_the_stack`, because we have created __an alias__: that is, another
`on_the_stack`, because we have created an alias: that is, another
name for the same data.

In contrast, we can pass `on_the_heap` to `compute_distance` directly.
The compiler automatically converts a box like `Box<Point>` to a reference like
`&Point`. This is another form of borrowing: in this case, the caller lends
the contents of the box to the callee.
For the second argument, we need to grab the contents of `on_the_heap`
by using the `*` operator, and then get a reference to that data. In
order to convert `Box<T>` into a `&T`, we need to use `&*`.

Whenever a caller lends data to a callee, there are some limitations on what
the caller can do with the original. For example, if the contents of a
Expand Down Expand Up @@ -166,12 +164,12 @@ as well as from the owned box, and then compute the distance between them.

# Lifetimes

We’ve seen a few examples of borrowing data. Up till this point, we’ve glossed
We’ve seen a few examples of borrowing data. To this point, we’ve glossed
over issues of safety. As stated in the introduction, at runtime a reference
is simply a pointer, nothing more. Therefore, avoiding C's problems with
dangling pointers requires a compile-time safety check.

The basis for the check is the notion of __lifetimes__. A lifetime is a
The basis for the check is the notion of _lifetimes_. A lifetime is a
static approximation of the span of execution during which the pointer
is valid: it always corresponds to some expression or block within the
program.
Expand Down Expand Up @@ -324,7 +322,7 @@ circle constant][tau] and not that dreadfully outdated notion of pi).

The second match is more interesting. Here we match against a
rectangle and extract its size: but rather than copy the `size`
struct, we use a __by-reference binding__ to create a pointer to it. In
struct, we use a by-reference binding to create a pointer to it. In
other words, a pattern binding like `ref size` binds the name `size`
to a pointer of type `&size` into the _interior of the enum_.

Expand Down
63 changes: 53 additions & 10 deletions src/doc/guide-pointers.md
Expand Up @@ -37,7 +37,7 @@ error: mismatched types: expected `&int` but found `<generic integer #0>` (expec

What gives? It needs a pointer! Therefore I have to use pointers!"

Turns out, you don't. __All you need is a reference__. Try this on for size:
Turns out, you don't. All you need is a reference. Try this on for size:

~~~rust
# fn succ(x: &int) -> int { *x + 1 }
Expand Down Expand Up @@ -74,8 +74,7 @@ Here are the use-cases for pointers. I've prefixed them with the name of the
pointer that satisfies that use-case:

1. Owned: `Box<Trait>` must be a pointer, because you don't know the size of the
object, so indirection is mandatory. Notation might change once Rust
support DST fully so we recommend you stay tuned.
object, so indirection is mandatory.

2. Owned: You need a recursive data structure. These can be infinite sized, so
indirection is mandatory.
Expand All @@ -89,7 +88,10 @@ common, such as C++, please read "A note..." below.
care about its ownership. If you make the argument a reference, callers
can send in whatever kind they want.

Four exceptions. That's it. Otherwise, you shouldn't need them. Be sceptical
5. Shared: You need to share data among tasks. You can achieve that via the
`Rc` and `Arc` types.

Five exceptions. That's it. Otherwise, you shouldn't need them. Be sceptical
of pointers in Rust: use them for a deliberate purpose, not just to make the
compiler happy.

Expand Down Expand Up @@ -205,10 +207,6 @@ The inner lists _must_ be an owned pointer, because we can't know how many
elements are in the list. Without knowing the length, we don't know the size,
and therefore require the indirection that pointers offer.

> Note: Nil is just part of the List enum and even though is being used
> to represent the concept of "nothing", you shouldn't think of it as
> NULL. Rust doesn't have NULL.
## Efficiency

This should almost never be a concern, but because creating an owned pointer
Expand Down Expand Up @@ -284,8 +282,8 @@ fn main() {
~~~

This prints `5.83095189`. You can see that the `compute_distance` function
takes in two references, but we give it a stack allocated reference and an
owned box reference.
takes in two references, a reference to a value on the stack, and a reference
to a value in a box.
Of course, if this were a real program, we wouldn't have any of these pointers,
they're just there to demonstrate the concepts.

Expand Down Expand Up @@ -361,6 +359,51 @@ hard for a computer, too! There is an entire [guide devoted to references
and lifetimes](guide-lifetimes.html) that goes into lifetimes in
great detail, so if you want the full details, check that out.

# Returning Pointers

We've talked a lot about functions that accept various kinds of pointers, but
what about returning them? In general, it is better to let the caller decide
how to use a function's output, instead of assuming a certain type of pointer
is best.

What does that mean? Don't do this:

~~~rust
fn foo(x: Box<int>) -> Box<int> {
return box *x;
}

fn main() {
let x = box 5;
let y = foo(x);
}
~~~

Do this:

~~~rust
fn foo(x: Box<int>) -> int {
return *x;
}

fn main() {
let x = box 5;
let y = box foo(x);
}
~~~

This gives you flexibility, without sacrificing performance.

You may think that this gives us terrible performance: return a value and then
immediately box it up ?! Isn't that the worst of both worlds? Rust is smarter
than that. There is no copy in this code. `main` allocates enough room for the
`box int`, passes a pointer to that memory into `foo` as `x`, and then `foo` writes
the value straight into that pointer. This writes the return value directly into
the allocated box.

This is important enough that it bears repeating: pointers are not for optimizing
returning values from your code. Allow the caller to choose how they want to
use your output.

# Related Resources

Expand Down

0 comments on commit 9974465

Please sign in to comment.