Skip to content

Commit 448c349

Browse files
committed
Copyedit sections 7 and 8 of the borrowed pointer tutorial
1 parent ae861f0 commit 448c349

File tree

1 file changed

+73
-69
lines changed

1 file changed

+73
-69
lines changed

doc/tutorial-borrowed-ptr.md

Lines changed: 73 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -447,11 +447,11 @@ the block restricts the scope of `y`, making the move legal.
447447

448448
# Borrowing and enums
449449

450-
The previous example showed that borrowing unique boxes found in
451-
aliasable, mutable memory is not permitted, so as to prevent pointers
452-
into freed memory. There is one other case where the compiler must be
453-
very careful to ensure that pointers remain valid: pointers into the
454-
interior of an enum.
450+
The previous example showed that the type system forbids any borrowing
451+
of unique boxes found in aliasable, mutable memory. This restriction
452+
prevents pointers from pointing into freed memory. There is one other
453+
case where the compiler must be very careful to ensure that pointers
454+
remain valid: pointers into the interior of an `enum`.
455455

456456
As an example, let’s look at the following `shape` type that can
457457
represent both rectangles and circles:
@@ -465,9 +465,9 @@ enum Shape {
465465
}
466466
~~~
467467

468-
Now I might write a function to compute the area of a shape. This
469-
function takes a borrowed pointer to a shape to avoid the need of
470-
copying them.
468+
Now we might write a function to compute the area of a shape. This
469+
function takes a borrowed pointer to a shape, to avoid the need for
470+
copying.
471471

472472
~~~
473473
# struct Point {x: float, y: float}; // as before
@@ -485,21 +485,21 @@ fn compute_area(shape: &Shape) -> float {
485485
}
486486
~~~
487487

488-
The first case matches against circles. Here the radius is extracted
489-
from the shape variant and used to compute the area of the circle
490-
(Like any up-to-date engineer, we use the [tau circle constant][tau]
491-
and not that dreadfully outdated notion of pi).
488+
The first case matches against circles. Here, the pattern extracts the
489+
radius from the shape variant and the action uses it to compute the
490+
area of the circle. (Like any up-to-date engineer, we use the [tau
491+
circle constant][tau] and not that dreadfully outdated notion of pi).
492492

493493
[tau]: http://www.math.utah.edu/~palais/pi.html
494494

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

501-
To make this more clear, lets look at a diagram of how things are
502-
laid out in memory in the case where `shape` points at a rectangle:
501+
To make this more clear, let's look at a diagram of memory layout in
502+
the case where `shape` points at a rectangle:
503503

504504
~~~ {.notrust}
505505
Stack Memory
@@ -523,8 +523,8 @@ the shape.
523523
Perhaps you can see where the danger lies: if the shape were somehow
524524
to be reassigned, perhaps to a circle, then although the memory used
525525
to store that shape value would still be valid, _it would have a
526-
different type_! This is shown in the following diagram, depicting what
527-
the state of memory would be if shape were overwritten with a circle:
526+
different type_! The following diagram shows what memory would look
527+
like if code overwrote `shape` with a circle:
528528

529529
~~~ {.notrust}
530530
Stack Memory
@@ -538,20 +538,23 @@ Stack Memory
538538
+---------------+
539539
~~~
540540

541-
As you can see, the `size` pointer would not be pointing at a `float` and
542-
not a struct. This is not good.
541+
As you can see, the `size` pointer would be pointing at a `float`
542+
instead of a struct. This is not good: dereferencing the second field
543+
of a `float` as if it were a struct with two fields would be a memory
544+
safety violation.
543545

544546
So, in fact, for every `ref` binding, the compiler will impose the
545547
same rules as the ones we saw for borrowing the interior of a unique
546-
box: it must be able to guarantee that the enum will not be
547-
overwritten for the duration of the borrow. In fact, the example I
548-
gave earlier would be considered safe. This is because the shape
549-
pointer has type `&Shape`, which means “borrowed pointer to immutable
550-
memory containing a shape”. If however the type of that pointer were
551-
`&const Shape` or `&mut Shape`, then the ref binding would not be
552-
permitted. Just as with unique boxes, the compiler will permit ref
553-
bindings into data owned by the stack frame even if it is mutable, but
554-
otherwise it requires that the data reside in immutable memory.
548+
box: it must be able to guarantee that the `enum` will not be
549+
overwritten for the duration of the borrow. In fact, the compiler
550+
would accept the example we gave earlier. The example is safe because
551+
the shape pointer has type `&Shape`, which means "borrowed pointer to
552+
immutable memory containing a `shape`". If, however, the type of that
553+
pointer were `&const Shape` or `&mut Shape`, then the ref binding
554+
would be ill-typed. Just as with unique boxes, the compiler will
555+
permit `ref` bindings into data owned by the stack frame even if the
556+
data are mutable, but otherwise it requires that the data reside in
557+
immutable memory.
555558

556559
> ***Note:*** Right now, pattern bindings not explicitly annotated
557560
> with `ref` or `copy` use a special mode of "implicit by reference".
@@ -560,11 +563,11 @@ otherwise it requires that the data reside in immutable memory.
560563
561564
# Returning borrowed pointers
562565

563-
So far, all of the examples weve looked at use borrowed pointers in a
564-
“downward” direction. That is, the borrowed pointer is created and
565-
then used during the method or code block which created it. It is also
566-
possible to return borrowed pointers to the caller, but as we'll see
567-
this requires some explicit annotation.
566+
So far, all of the examples we've looked at use borrowed pointers in a
567+
“downward” direction. That is, a method or code block creates a
568+
borrowed pointer, then uses it within the same scope. It is also
569+
possible to return borrowed pointers as the result of a function, but
570+
as we'll see, doing so requires some explicit annotation.
568571

569572
For example, we could write a subroutine like this:
570573

@@ -573,23 +576,25 @@ struct Point {x: float, y: float}
573576
fn get_x(p: &r/Point) -> &r/float { &p.x }
574577
~~~
575578

576-
Here, the function `get_x()` returns a pointer into the structure it was
577-
given. The type of the parameter (`&r/Point`) and return type (`&r/float`) both
578-
make use of a new syntactic form that we have not seen so far. Here the identifier `r`
579-
serves as an explicit name for the lifetime of the pointer. So in effect
580-
this function is declaring that it takes in a pointer with lifetime `r` and returns
581-
a pointer with that same lifetime.
579+
Here, the function `get_x()` returns a pointer into the structure it
580+
was given. The type of the parameter (`&r/Point`) and return type
581+
(`&r/float`) both use a new syntactic form that we have not seen so
582+
far. Here the identifier `r` names the lifetime of the pointer
583+
explicitly. So in effect, this function declares that it takes a
584+
pointer with lifetime `r` and returns a pointer with that same
585+
lifetime.
582586

583587
In general, it is only possible to return borrowed pointers if they
584-
are derived from a borrowed pointer which was given as input to the
585-
procedure. In that case, they will always have the same lifetime as
586-
one of the parameters; named lifetimes are used to indicate which
587-
parameter that is.
588+
are derived from a parameter to the procedure. In that case, the
589+
pointer result will always have the same lifetime as one of the
590+
parameters; named lifetimes indicate which parameter that
591+
is.
588592

589-
In the examples before, function parameter types did not include a
590-
lifetime name. In this case, the compiler simply creates a new,
591-
anonymous name, meaning that the parameter is assumed to have a
592-
distinct lifetime from all other parameters.
593+
In the previous examples, function parameter types did not include a
594+
lifetime name. In those examples, the compiler simply creates a fresh
595+
name for the lifetime automatically: that is, the lifetime name is
596+
guaranteed to refer to a distinct lifetime from the lifetimes of all
597+
other parameters.
593598

594599
Named lifetimes that appear in function signatures are conceptually
595600
the same as the other lifetimes we've seen before, but they are a bit
@@ -599,13 +604,13 @@ lifetime `r` is actually a kind of *lifetime parameter*: it is defined
599604
by the caller to `get_x()`, just as the value for the parameter `p` is
600605
defined by that caller.
601606

602-
In any case, whatever the lifetime `r` is, the pointer produced by
603-
`&p.x` always has the same lifetime as `p` itself, as a pointer to a
607+
In any case, whatever the lifetime of `r` is, the pointer produced by
608+
`&p.x` always has the same lifetime as `p` itself: a pointer to a
604609
field of a struct is valid as long as the struct is valid. Therefore,
605-
the compiler is satisfied with the function `get_x()`.
610+
the compiler accepts the function `get_x()`.
606611

607-
To drill in this point, let’s look at a variation on the example, this
608-
time one which does not compile:
612+
To emphasize this point, let’s look at a variation on the example, this
613+
time one that does not compile:
609614

610615
~~~ {.xfail-test}
611616
struct Point {x: float, y: float}
@@ -617,22 +622,21 @@ fn get_x_sh(p: @Point) -> &float {
617622
Here, the function `get_x_sh()` takes a managed box as input and
618623
returns a borrowed pointer. As before, the lifetime of the borrowed
619624
pointer that will be returned is a parameter (specified by the
620-
caller). That means that effectively `get_x_sh()` is promising to
621-
return a borrowed pointer that is valid for as long as the caller
622-
would like: this is subtly different from the first example, which
623-
promised to return a pointer that was valid for as long as the pointer
624-
it was given.
625+
caller). That means that `get_x_sh()` promises to return a borrowed
626+
pointer that is valid for as long as the caller would like: this is
627+
subtly different from the first example, which promised to return a
628+
pointer that was valid for as long as its pointer argument was valid.
625629

626630
Within `get_x_sh()`, we see the expression `&p.x` which takes the
627-
address of a field of a managed box. This implies that the compiler
628-
must guarantee that, so long as the resulting pointer is valid, the
629-
managed box will not be reclaimed by the garbage collector. But recall
630-
that `get_x_sh()` also promised to return a pointer that was valid for
631-
as long as the caller wanted it to be. Clearly, `get_x_sh()` is not in
632-
a position to make both of these guarantees; in fact, it cannot
633-
guarantee that the pointer will remain valid at all once it returns,
634-
as the parameter `p` may or may not be live in the caller. Therefore,
635-
the compiler will report an error here.
631+
address of a field of a managed box. The presence of this expression
632+
implies that the compiler must guarantee that, so long as the
633+
resulting pointer is valid, the managed box will not be reclaimed by
634+
the garbage collector. But recall that `get_x_sh()` also promised to
635+
return a pointer that was valid for as long as the caller wanted it to
636+
be. Clearly, `get_x_sh()` is not in a position to make both of these
637+
guarantees; in fact, it cannot guarantee that the pointer will remain
638+
valid at all once it returns, as the parameter `p` may or may not be
639+
live in the caller. Therefore, the compiler will report an error here.
636640

637641
In general, if you borrow a managed (or unique) box to create a
638642
borrowed pointer, the pointer will only be valid within the function

0 commit comments

Comments
 (0)