]> git.lizzy.rs Git - rust.git/commitdiff
Update guide/intro to take into account the removal of `proc`.
authorNiko Matsakis <niko@alum.mit.edu>
Wed, 26 Nov 2014 15:02:46 +0000 (10:02 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Sun, 14 Dec 2014 09:21:57 +0000 (04:21 -0500)
cc @steveklabnick

src/doc/guide-tasks.md
src/doc/guide.md
src/doc/intro.md
src/doc/reference.md

index 1938d3e38783fd2ac305dd78de5f49d6181b96f3..4adca43be18e946baa973d260903aedad5af58a3 100644 (file)
@@ -30,7 +30,7 @@ fn print_message() { println!("I am running in a different task!"); }
 spawn(print_message);
 
 // Alternatively, use a `move ||` expression instead of a named function.
-// `||` expressions evaluate to an unnamed closures. The `move` keyword
+// `||` expressions evaluate to an unnamed closure. The `move` keyword
 // indicates that the closure should take ownership of any variables it
 // touches.
 spawn(move || println!("I am also running in a different task!"));
@@ -44,7 +44,7 @@ details to the standard library.
 The `spawn` function has the type signature: `fn
 spawn<F:FnOnce()+Send>(f: F)`.  This indicates that it takes as
 argument a closure (of type `F`) that it will run exactly once. This
-closure is limited to capturing `Send`-able data form its environment
+closure is limited to capturing `Send`-able data from its environment
 (that is, data which is deeply owned). Limiting the closure to `Send`
 ensures that `spawn` can safely move the entire closure and all its
 associated state into an entirely different task for execution.
index 21043cfef1480e6b41b97963f0f5ce44aade292e..6e178a2648dbfb1ab20c2bb1db9c56b2c553a266 100644 (file)
@@ -4235,36 +4235,16 @@ fn main() {
 }
 ```
 
-## Procs
+## Moving closures
 
-Rust has a second type of closure, called a **proc**. Procs are created
-with the `proc` keyword:
-
-```{rust}
-let x = 5i;
-
-let p = proc() { x * x };
-println!("{}", p()); // prints 25
-```
-
-There is a big difference between procs and closures: procs may only be called once. This
-will error when we try to compile:
-
-```{rust,ignore}
-let x = 5i;
-
-let p = proc() { x * x };
-println!("{}", p());
-println!("{}", p()); // error: use of moved value `p`
-```
-
-This restriction is important. Procs are allowed to consume values that they
-capture, and thus have to be restricted to being called once for soundness
-reasons: any value consumed would be invalid on a second call.
-
-Procs are most useful with Rust's concurrency features, and so we'll just leave
-it at this for now. We'll talk about them more in the "Tasks" section of the
-guide.
+Rust has a second type of closure, called a **moving closure**. Moving
+closures are indicated using the `move` keyword (e.g., `move || x *
+x`). The difference between a moving closure and an ordinary closure
+is that a moving closure always takes ownership of all variables that
+it uses. Ordinary closures, in contrast, just create a reference into
+the enclosing stack frame. Moving closures are most useful with Rust's
+concurrency features, and so we'll just leave it at this for
+now. We'll talk about them more in the "Tasks" section of the guide.
 
 ## Accepting closures as arguments
 
@@ -5231,28 +5211,30 @@ concurrency libraries can be written for Rust to help in specific scenarios.
 Here's an example of creating a task:
 
 ```{rust}
-spawn(proc() {
+spawn(move || {
     println!("Hello from a task!");
 });
 ```
 
-The `spawn` function takes a proc as an argument, and runs that proc in a new
-task. A proc takes ownership of its entire environment, and so any variables
-that you use inside the proc will not be usable afterward:
+The `spawn` function takes a closure as an argument, and runs that
+closure in a new task. Typically, you will want to use a moving
+closure, so that the closure takes ownership of any variables that it
+touches.  This implies that those variables are not usable from the
+parent task after the child task is spawned:
 
 ```{rust,ignore}
 let mut x = vec![1i, 2i, 3i];
 
-spawn(proc() {
+spawn(move || {
     println!("The value of x[0] is: {}", x[0]);
 });
 
 println!("The value of x[0] is: {}", x[0]); // error: use of moved value: `x`
 ```
 
-`x` is now owned by the proc, and so we can't use it anymore. Many other
-languages would let us do this, but it's not safe to do so. Rust's borrow
-checker catches the error.
+`x` is now owned by the closure, and so we can't use it anymore. Many
+other languages would let us do this, but it's not safe to do
+so. Rust's borrow checker catches the error.
 
 If tasks were only able to capture these values, they wouldn't be very useful.
 Luckily, tasks can communicate with each other through **channel**s. Channels
@@ -5261,7 +5243,7 @@ work like this:
 ```{rust}
 let (tx, rx) = channel();
 
-spawn(proc() {
+spawn(move || {
     tx.send("Hello from a task!".to_string());
 });
 
@@ -5281,7 +5263,7 @@ If you want to send messages to the task as well, create two channels!
 let (tx1, rx1) = channel();
 let (tx2, rx2) = channel();
 
-spawn(proc() {
+spawn(move || {
     tx1.send("Hello from a task!".to_string());
     let message = rx2.recv();
     println!("{}", message);
@@ -5293,8 +5275,9 @@ println!("{}", message);
 tx2.send("Goodbye from main!".to_string());
 ```
 
-The proc has one sending end and one receiving end, and the main task has one
-of each as well. Now they can talk back and forth in whatever way they wish.
+The closure has one sending end and one receiving end, and the main
+task has one of each as well. Now they can talk back and forth in
+whatever way they wish.
 
 Notice as well that because `Sender` and `Receiver` are generic, while you can
 pass any kind of information through the channel, the ends are strongly typed.
@@ -5310,7 +5293,7 @@ a useful thing to use:
 ```{rust}
 use std::sync::Future;
 
-let mut delayed_value = Future::spawn(proc() {
+let mut delayed_value = Future::spawn(move || {
     // just return anything for examples' sake
 
     12345i
@@ -5318,18 +5301,18 @@ let mut delayed_value = Future::spawn(proc() {
 println!("value = {}", delayed_value.get());
 ```
 
-Calling `Future::spawn` works just like `spawn()`: it takes a proc. In this
-case, though, you don't need to mess with the channel: just have the proc
-return the value.
+Calling `Future::spawn` works just like `spawn()`: it takes a
+closure. In this case, though, you don't need to mess with the
+channel: just have the closure return the value.
 
 `Future::spawn` will return a value which we can bind with `let`. It needs
 to be mutable, because once the value is computed, it saves a copy of the
 value, and if it were immutable, it couldn't update itself.
 
-The proc will go on processing in the background, and when we need the final
-value, we can call `get()` on it. This will block until the result is done,
-but if it's finished computing in the background, we'll just get the value
-immediately.
+The future will go on processing in the background, and when we need
+the final value, we can call `get()` on it. This will block until the
+result is done, but if it's finished computing in the background,
+we'll just get the value immediately.
 
 ## Success and failure
 
@@ -5337,7 +5320,7 @@ Tasks don't always succeed, they can also panic. A task that wishes to panic
 can call the `panic!` macro, passing a message:
 
 ```{rust}
-spawn(proc() {
+spawn(move || {
     panic!("Nope.");
 });
 ```
@@ -5349,7 +5332,7 @@ notify other tasks that it has panicked. We can do this with `task::try`:
 use std::task;
 use std::rand;
 
-let result = task::try(proc() {
+let result = task::try(move || {
     if rand::random() {
         println!("OK");
     } else {
index e2cccef5b4a1d13afadaf7546874bd4660df5c7d..c0a1d5fa8816f7e9e6a2936bbc93b8389af3f13f 100644 (file)
@@ -391,26 +391,29 @@ Here's an example of a concurrent Rust program:
 ```{rust}
 fn main() {
     for _ in range(0u, 10u) {
-        spawn(proc() {
+        spawn(move || {
             println!("Hello, world!");
         });
     }
 }
 ```
 
-This program creates ten threads, who all print `Hello, world!`. The `spawn`
-function takes one argument, a `proc`. 'proc' is short for 'procedure,' and is
-a form of closure. This closure is executed in a new thread, created by `spawn`
-itself.
-
-One common form of problem in concurrent programs is a 'data race.' This occurs
-when two different threads attempt to access the same location in memory in a
-non-synchronized way, where at least one of them is a write. If one thread is
-attempting to read, and one thread is attempting to write, you cannot be sure
-that your data will not be corrupted. Note the first half of that requirement:
-two threads that attempt to access the same location in memory. Rust's
-ownership model can track which pointers own which memory locations, which
-solves this problem.
+This program creates ten threads, who all print `Hello, world!`. The
+`spawn` function takes one argument, a closure, indicated by the
+double bars `||`. (The `move` keyword indicates that the closure takes
+ownership of any data it uses; we'll have more on the significance of
+this shortly.) This closure is executed in a new thread created by
+`spawn`.
+
+One common form of problem in concurrent programs is a 'data race.'
+This occurs when two different threads attempt to access the same
+location in memory in a non-synchronized way, where at least one of
+them is a write. If one thread is attempting to read, and one thread
+is attempting to write, you cannot be sure that your data will not be
+corrupted. Note the first half of that requirement: two threads that
+attempt to access the same location in memory. Rust's ownership model
+can track which pointers own which memory locations, which solves this
+problem.
 
 Let's see an example. This Rust code will not compile:
 
@@ -419,7 +422,7 @@ fn main() {
     let mut numbers = vec![1i, 2i, 3i];
 
     for i in range(0u, 3u) {
-        spawn(proc() {
+        spawn(move || {
             for j in range(0, 3) { numbers[j] += 1 }
         });
     }
@@ -432,8 +435,8 @@ It gives us this error:
 6:71 error: capture of moved value: `numbers`
     for j in range(0, 3) { numbers[j] += 1 }
                ^~~~~~~
-7:50 note: `numbers` moved into closure environment here because it has type `proc():Send`, which is non-copyable (perhaps you meant to use clone()?)
-    spawn(proc() {
+7:50 note: `numbers` moved into closure environment here
+    spawn(move || {
         for j in range(0, 3) { numbers[j] += 1 }
     });
 6:79 error: cannot assign to immutable dereference (dereference is implicit, due to indexing)
@@ -441,11 +444,16 @@ It gives us this error:
                            ^~~~~~~~~~~~~~~
 ```
 
-It mentions that "numbers moved into closure environment". Because we referred
-to `numbers` inside of our `proc`, and we create three `proc`s, we would have
-three references. Rust detects this and gives us the error: we claim that
-`numbers` has ownership, but our code tries to make three owners. This may
-cause a safety problem, so Rust disallows it.
+It mentions that "numbers moved into closure environment". Because we
+declared the closure as a moving closure, and it referred to
+`numbers`, the closure will try to take ownership of the vector. But
+the closure itself is created in a loop, and hence we will actually
+create three closures, one for every iteration of the loop. This means
+that all three of those closures would try to own `numbers`, which is
+impossible -- `numbers` must have just one owner. Rust detects this
+and gives us the error: we claim that `numbers` has ownership, but our
+code tries to make three owners. This may cause a safety problem, so
+Rust disallows it.
 
 What to do here? Rust has two types that helps us: `Arc<T>` and `Mutex<T>`.
 "Arc" stands for "atomically reference counted." In other words, an Arc will
@@ -468,7 +476,7 @@ fn main() {
 
     for i in range(0u, 3u) {
         let number = numbers.clone();
-        spawn(proc() {
+        spawn(move || {
             let mut array = number.lock();
 
             (*array)[i] += 1;
@@ -528,7 +536,7 @@ fn main() {
     let vec = vec![1i, 2, 3];
 
     for i in range(1u, 3) {
-        spawn(proc() {
+        spawn(move || {
             println!("{}", vec[i]);
         });
     }
index ee70981d9b254b05e0e490d36c1ae5b20910b316..c24cd6d8bf3911f9a1d5bc4527a67f27fd88910c 100644 (file)
@@ -187,19 +187,18 @@ grammar as double-quoted strings. Other tokens have exact rules given.
 
 <p id="keyword-table-marker"></p>
 
-|          |          |          |          |        |
-|----------|----------|----------|----------|--------|
-| abstract | alignof  | as       | be       | box    |
-| break    | const    | continue | crate    | do     |
-| else     | enum     | extern   | false    | final  |
-| fn       | for      | if       | impl     | in     |
-| let      | loop     | match    | mod      | move   |
-| mut      | offsetof | once     | override | priv   |
-| proc     | pub      | pure     | ref      | return |
-| sizeof   | static   | self     | struct   | super  |
-| true     | trait    | type     | typeof   | unsafe |
-| unsized  | use      | virtual  | where    | while  |
-| yield    |          |          |          |        |
+|          |          |          |          |         |
+|----------|----------|----------|----------|---------|
+| abstract | alignof  | as       | be       | box     |
+| break    | const    | continue | crate    | do      |
+| else     | enum     | extern   | false    | final   |
+| fn       | for      | if       | impl     | in      |
+| let      | loop     | match    | mod      | move    |
+| mut      | offsetof | once     | override | priv    |
+| pub      | pure     | ref      | return   | sizeof  |
+| static   | self     | struct   | super    | true    |
+| trait    | type     | typeof   | unsafe   | unsized |
+| use      | virtual  | where    | while    | yield   |
 
 
 Each of these keywords has special meaning in its grammar, and all of them are
@@ -3842,8 +3841,6 @@ x = bo(5,7);
 ```{.ebnf .notation}
 closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|'
                 [ ':' bound-list ] [ '->' type ]
-procedure_type := 'proc' [ '<' lifetime-list '>' ] '(' arg-list ')'
-                  [ ':' bound-list ] [ '->' type ]
 lifetime-list := lifetime | lifetime ',' lifetime-list
 arg-list := ident ':' type | ident ':' type ',' arg-list
 bound-list := bound | bound '+' bound-list
@@ -3852,8 +3849,6 @@ bound := path | lifetime
 
 The type of a closure mapping an input of type `A` to an output of type `B` is
 `|A| -> B`. A closure with no arguments or return values has type `||`.
-Similarly, a procedure mapping `A` to `B` is `proc(A) -> B` and a no-argument
-and no-return value closure has type `proc()`.
 
 An example of creating and calling a closure:
 
@@ -3876,30 +3871,6 @@ call_closure(closure_no_args, closure_args);
 
 ```
 
-Unlike closures, procedures may only be invoked once, but own their
-environment, and are allowed to move out of their environment. Procedures are
-allocated on the heap (unlike closures). An example of creating and calling a
-procedure:
-
-```rust
-let string = "Hello".to_string();
-
-// Creates a new procedure, passing it to the `spawn` function.
-spawn(proc() {
-  println!("{} world!", string);
-});
-
-// the variable `string` has been moved into the previous procedure, so it is
-// no longer usable.
-
-
-// Create an invoke a procedure. Note that the procedure is *moved* when
-// invoked, so it cannot be invoked again.
-let f = proc(n: int) { n + 22 };
-println!("answer: {}", f(20));
-
-```
-
 ### Object types
 
 Every trait item (see [traits](#traits)) defines a type with the same name as