Skip to content

Commit 29033cc

Browse files
committed
---
yaml --- r: 139135 b: refs/heads/try2 c: 64d923f h: refs/heads/master i: 139133: 92830fd 139131: 0b23853 139127: f7e7079 139119: 8cdfc83 139103: 2f00f36 139071: b4eca56 139007: ec0376a v: v3
1 parent b44f97c commit 29033cc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+2499
-3264
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ refs/heads/snap-stage3: 78a7676898d9f80ab540c6df5d4c9ce35bb50463
55
refs/heads/try: 519addf6277dbafccbb4159db4b710c37eaa2ec5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
8-
refs/heads/try2: 1fa2b9980fabff3227d5e5915d1180a0f6922d37
8+
refs/heads/try2: 64d923f7ddf467e5dfa1999329362c42c892bf3d
99
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try2/doc/tutorial.md

Lines changed: 130 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -853,184 +853,170 @@ as in this example that unpacks the first value from a tuple and returns it.
853853
fn first((value, _): (int, float)) -> int { value }
854854
~~~
855855

856-
# Destructors
856+
# Boxes and pointers
857+
858+
Many modern languages have a so-called "uniform representation" for
859+
aggregate types like structs and enums, so as to represent these types
860+
as pointers to heap memory by default. In contrast, Rust, like C and
861+
C++, represents such types directly. Another way to say this is that
862+
aggregate data in Rust are *unboxed*. This means that if you `let x =
863+
Point { x: 1f, y: 1f };`, you are creating a struct on the stack. If you
864+
then copy it into a data structure, you copy the entire struct, not
865+
just a pointer.
866+
867+
For small structs like `Point`, this is usually more efficient than
868+
allocating memory and indirecting through a pointer. But for big structs, or
869+
those with mutable fields, it can be useful to have a single copy on
870+
the stack or on the heap, and refer to that through a pointer.
871+
872+
Whenever memory is allocated on the heap, the program needs a strategy to
873+
dispose of the memory when no longer needed. Most languages, such as Java or
874+
Python, use *garbage collection* for this, a strategy in which the program
875+
periodically searches for allocations that are no longer reachable in order
876+
to dispose of them. Other languages, such as C, use *manual memory
877+
management*, which relies on the programmer to specify when memory should be
878+
reclaimed.
879+
880+
Rust is in a different position. It differs from the garbage-collected
881+
environments in that allows the programmer to choose the disposal
882+
strategy on an object-by-object basis. Not only does this have benefits for
883+
performance, but we will later see that this model has benefits for
884+
concurrency as well, by making it possible for the Rust compiler to detect
885+
data races at compile time. Rust also differs from the manually managed
886+
languages in that it is *safe*—it uses a [pointer lifetime
887+
analysis][borrow] to ensure that manual memory management cannot cause memory
888+
errors at runtime.
857889

858-
C-style resource management requires the programmer to match every allocation
859-
with a free, which means manually tracking the responsibility for cleaning up
860-
(the owner). Correctness is left to the programmer, and it's easy to get wrong.
861-
862-
The following code demonstrates manual memory management, in order to contrast
863-
it with Rust's resource management. Rust enforces safety, so the `unsafe`
864-
keyword is used to explicitly wrap the unsafe code. The keyword is a promise to
865-
the compiler that unsafety does not leak outside of the unsafe block, and is
866-
used to create safe concepts on top of low-level code.
890+
[borrow]: tutorial-borrowed-ptr.html
867891

868-
~~~~
869-
use core::libc::funcs::c95::stdlib::{calloc, free};
870-
use core::libc::types::os::arch::c95::size_t;
892+
The cornerstone of Rust's memory management is the concept of a *smart
893+
pointer*—a pointer type that indicates the lifetime of the object it points
894+
to. This solution is familiar to C++ programmers; Rust differs from C++,
895+
however, in that a small set of smart pointers are built into the language.
896+
The safe pointer types are `@T`, for *managed* boxes allocated on the *local
897+
heap*, `~T`, for *uniquely-owned* boxes allocated on the *exchange
898+
heap*, and `&T`, for *borrowed* pointers, which may point to any memory, and
899+
whose lifetimes are governed by the call stack.
871900

872-
fn main() {
873-
unsafe {
874-
let a = calloc(1, int::bytes as size_t);
901+
All pointer types can be dereferenced with the `*` unary operator.
875902

876-
let d;
903+
> ***Note***: You may also hear managed boxes referred to as 'shared
904+
> boxes' or 'shared pointers', and owned boxes as 'unique boxes/pointers'.
905+
> Borrowed pointers are sometimes called 'region pointers'. The preferred
906+
> terminology is what we present here.
877907
878-
{
879-
let b = calloc(1, int::bytes as size_t);
880-
881-
let c = calloc(1, int::bytes as size_t);
882-
d = c; // move ownership to d
908+
## Managed boxes
883909

884-
free(b);
885-
}
910+
Managed boxes are pointers to heap-allocated, garbage-collected
911+
memory. Applying the unary `@` operator to an expression creates a
912+
managed box. The resulting box contains the result of the
913+
expression. Copying a managed box, as happens during assignment, only
914+
copies a pointer, never the contents of the box.
886915

887-
free(d);
888-
free(a);
889-
}
890-
}
891916
~~~~
917+
let x: @int = @10; // New box
918+
let y = x; // Copy of a pointer to the same box
892919
893-
Rust uses destructors to handle the release of resources like memory
894-
allocations, files and sockets. An object will only be destroyed when there is
895-
no longer any way to access it, which prevents dynamic failures from an attempt
896-
to use a freed resource. When a task fails, the stack unwinds and the
897-
destructors of all objects owned by that task are called.
898-
899-
The unsafe code from above can be contained behind a safe API that prevents
900-
memory leaks or use-after-free:
901-
920+
// x and y both refer to the same allocation. When both go out of scope
921+
// then the allocation will be freed.
902922
~~~~
903-
use core::libc::funcs::c95::stdlib::{calloc, free};
904-
use core::libc::types::common::c95::c_void;
905-
use core::libc::types::os::arch::c95::size_t;
906923

907-
struct Blob { priv ptr: *c_void }
924+
A _managed_ type is either of the form `@T` for some type `T`, or any
925+
type that contains managed boxes or other managed types.
908926

909-
impl Blob {
910-
static fn new() -> Blob {
911-
unsafe { Blob{ptr: calloc(1, int::bytes as size_t)} }
912-
}
927+
~~~
928+
// A linked list node
929+
struct Node {
930+
next: MaybeNode,
931+
prev: MaybeNode,
932+
payload: int
913933
}
914934
915-
impl Drop for Blob {
916-
fn finalize(&self) {
917-
unsafe { free(self.ptr); }
918-
}
935+
enum MaybeNode {
936+
SomeNode(@mut Node),
937+
NoNode
919938
}
920939
921-
fn main() {
922-
let a = Blob::new();
923-
924-
let d;
940+
let node1 = @mut Node { next: NoNode, prev: NoNode, payload: 1 };
941+
let node2 = @mut Node { next: NoNode, prev: NoNode, payload: 2 };
942+
let node3 = @mut Node { next: NoNode, prev: NoNode, payload: 3 };
925943
926-
{
927-
let b = Blob::new();
944+
// Link the three list nodes together
945+
node1.next = SomeNode(node2);
946+
node2.prev = SomeNode(node1);
947+
node2.next = SomeNode(node3);
948+
node3.prev = SomeNode(node2);
949+
~~~
928950

929-
let c = Blob::new();
930-
d = c; // move ownership to d
951+
Managed boxes never cross task boundaries. This has several benefits for
952+
performance:
931953

932-
// b is destroyed here
933-
}
954+
* The Rust garbage collector does not need to stop multiple threads in order
955+
to collect garbage.
934956

935-
// d is destroyed here
936-
// a is destroyed here
937-
}
938-
~~~~
957+
* You can separate your application into "real-time" tasks that do not use
958+
the garbage collector and "non-real-time" tasks that do, and the real-time
959+
tasks will not be interrupted by the non-real-time tasks.
939960

940-
This pattern is common enough that Rust includes dynamically allocated memory
941-
as first-class types (`~` and `@`). Non-memory resources like files are cleaned
942-
up with custom destructors.
961+
C++ programmers will recognize `@T` as similar to `std::shared_ptr<T>`.
943962

944-
~~~~
945-
fn main() {
946-
let a = ~0;
963+
> ***Note:*** Currently, the Rust compiler generates code to reclaim
964+
> managed boxes through reference counting and a cycle collector, but
965+
> we will switch to a tracing garbage collector eventually.
947966
948-
let d;
967+
## Owned boxes
949968

950-
{
951-
let b = ~0;
969+
In contrast with managed boxes, owned boxes have a single owning
970+
memory slot and thus two owned boxes may not refer to the same
971+
memory. All owned boxes across all tasks are allocated on a single
972+
_exchange heap_, where their uniquely-owned nature allows tasks to
973+
exchange them efficiently.
952974

953-
let c = ~0;
954-
d = c; // move ownership to d
975+
Because owned boxes are uniquely owned, copying them requires allocating
976+
a new owned box and duplicating the contents.
977+
Instead, owned boxes are _moved_ by default, transferring ownership,
978+
and deinitializing the previously owning variable.
979+
Any attempt to access a variable after the value has been moved out
980+
will result in a compile error.
955981

956-
// b is destroyed here
957-
}
958-
959-
// d is destroyed here
960-
// a is destroyed here
961-
}
982+
~~~~
983+
let x = ~10;
984+
// Move x to y, deinitializing x
985+
let y = x;
962986
~~~~
963987

964-
# Ownership
965-
966-
Rust formalizes the concept of object ownership to delegate management of an
967-
object's lifetime to either a variable or a task-local garbage collector. An
968-
object's owner is responsible for managing the lifetime of the object by
969-
calling the destructor, and the owner determines whether the object is mutable.
970-
971-
Ownership is recursive, so mutability is inherited recursively and a destructor
972-
destroys the contained tree of owned objects. Variables are top-level owners
973-
and destroy the contained object when they go out of scope. A box managed by
974-
the garbage collector starts a new ownership tree, and the destructor is called
975-
when it is collected.
976-
977-
If an object doesn't contain garbage-collected boxes, it consists of a single
978-
ownership tree and is given the `Owned` trait which allows it to be sent
979-
between tasks.
980-
981-
# Boxes
982-
983-
Many modern languages represent values as as pointers to heap memory by
984-
default. In contrast, Rust, like C and C++, represents such types directly.
985-
Another way to say this is that aggregate data in Rust are *unboxed*. This
986-
means that if you `let x = Point { x: 1f, y: 1f };`, you are creating a struct
987-
on the stack. If you then copy it into a data structure, you copy the entire
988-
struct, not just a pointer.
989-
990-
For small structs like `Point`, this is usually more efficient than allocating
991-
memory and indirecting through a pointer. But for big structs, or mutable
992-
state, it can be useful to have a single copy on the stack or on the heap, and
993-
refer to that through a pointer.
994-
995-
## Owned boxes
996-
997-
An owned box (`~`) is a uniquely owned allocation on the heap. An owned box
998-
inherits the mutability and lifetime of the owner as it would if there was no
999-
box. The purpose of an owned box is to add a layer of indirection in order to
1000-
create recursive data structures or cheaply pass around an object larger than a
1001-
pointer.
988+
If you really want to copy an owned box you must say so explicitly.
1002989

1003-
## Managed boxes
990+
~~~~
991+
let x = ~10;
992+
let y = copy x;
1004993
1005-
A managed box (`@`) is a heap allocation with the lifetime managed by a
1006-
task-local garbage collector. It will be destroyed at some point after there
1007-
are no references left to the box, no later than the end of the task. Managed
1008-
boxes lack an owner, so they start a new ownership tree and don't inherit
1009-
mutability. They do own the contained object, and mutability is defined by the
1010-
type of the shared box (`@` or `@mut`). An object containing a managed box is
1011-
not `Owned`, and can't be sent between tasks.
994+
let z = *x + *y;
995+
fail_unless!(z == 20);
996+
~~~~
1012997

1013-
# Move semantics
998+
When they do not contain any managed boxes, owned boxes can be sent
999+
to other tasks. The sending task will give up ownership of the box
1000+
and won't be able to access it afterwards. The receiving task will
1001+
become the sole owner of the box. This prevents *data races*—errors
1002+
that could otherwise result from multiple tasks working on the same
1003+
data without synchronization.
10141004

1015-
Rust uses a shallow copy for parameter passing, assignment and returning values
1016-
from functions. A shallow copy is considered a move of ownership if the
1017-
ownership tree of the copied value includes an owned box or a type with a
1018-
custom destructor. After a value has been moved, it can no longer be used from
1019-
the source location and will not be destroyed there.
1005+
When an owned pointer goes out of scope or is overwritten, the object
1006+
it points to is immediately freed. Effective use of owned boxes can
1007+
therefore be an efficient alternative to garbage collection.
10201008

1021-
~~~~
1022-
let x = ~5;
1023-
let y = x.clone(); // y is a newly allocated box
1024-
let z = x; // no new memory allocated, x can no longer be used
1025-
~~~~
1009+
C++ programmers will recognize `~T` as similar to `std::unique_ptr<T>`
1010+
(or `std::auto_ptr<T>` in C++03 and below).
10261011

1027-
# Borrowed pointers
1012+
## Borrowed pointers
10281013

1029-
Rust's borrowed pointers are a general purpose reference type. In contrast with
1030-
owned pointers, where the holder of an owned pointer is the owner of the
1031-
pointed-to memory, borrowed pointers never imply ownership. A pointer can be
1032-
borrowed to any object, and the compiler verifies that it cannot outlive the
1033-
lifetime of the object.
1014+
Rust borrowed pointers are a general purpose reference/pointer type,
1015+
similar to the C++ reference type, but guaranteed to point to valid
1016+
memory. In contrast with owned pointers, where the holder of an owned
1017+
pointer is the owner of the pointed-to memory, borrowed pointers never
1018+
imply ownership. Pointers may be borrowed from any type, in which case
1019+
the pointer is guaranteed not to outlive the value it points to.
10341020

10351021
As an example, consider a simple struct type, `Point`:
10361022

@@ -1113,23 +1099,7 @@ For a more in-depth explanation of borrowed pointers, read the
11131099
11141100
[borrowtut]: tutorial-borrowed-ptr.html
11151101
1116-
## Freezing
1117-
1118-
Borrowing an immutable pointer to an object freezes it and prevents mutation.
1119-
`Owned` objects have freezing enforced statically at compile-time. Mutable
1120-
managed boxes handle freezing dynamically when any of their contents are
1121-
borrowed, and the task will fail if an attempt to modify them is made while
1122-
they are frozen.
1123-
1124-
~~~~
1125-
let mut x = 5;
1126-
{
1127-
let y = &x; // x is now frozen, it cannot be modified
1128-
}
1129-
// x is now unfrozen again
1130-
~~~~
1131-
1132-
# Dereferencing pointers
1102+
## Dereferencing pointers
11331103
11341104
Rust uses the unary star operator (`*`) to access the contents of a
11351105
box or pointer, similarly to C.

0 commit comments

Comments
 (0)