Skip to content

Commit 112faab

Browse files
committed
Update guide/intro to take into account the removal of proc.
cc @steveklabnick
1 parent 27676d9 commit 112faab

File tree

4 files changed

+80
-118
lines changed

4 files changed

+80
-118
lines changed

src/doc/guide-tasks.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fn print_message() { println!("I am running in a different task!"); }
3030
spawn(print_message);
3131
3232
// Alternatively, use a `move ||` expression instead of a named function.
33-
// `||` expressions evaluate to an unnamed closures. The `move` keyword
33+
// `||` expressions evaluate to an unnamed closure. The `move` keyword
3434
// indicates that the closure should take ownership of any variables it
3535
// touches.
3636
spawn(move || println!("I am also running in a different task!"));
@@ -44,7 +44,7 @@ details to the standard library.
4444
The `spawn` function has the type signature: `fn
4545
spawn<F:FnOnce()+Send>(f: F)`. This indicates that it takes as
4646
argument a closure (of type `F`) that it will run exactly once. This
47-
closure is limited to capturing `Send`-able data form its environment
47+
closure is limited to capturing `Send`-able data from its environment
4848
(that is, data which is deeply owned). Limiting the closure to `Send`
4949
ensures that `spawn` can safely move the entire closure and all its
5050
associated state into an entirely different task for execution.

src/doc/guide.md

Lines changed: 34 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4235,36 +4235,16 @@ fn main() {
42354235
}
42364236
```
42374237

4238-
## Procs
4238+
## Moving closures
42394239

4240-
Rust has a second type of closure, called a **proc**. Procs are created
4241-
with the `proc` keyword:
4242-
4243-
```{rust}
4244-
let x = 5i;
4245-
4246-
let p = proc() { x * x };
4247-
println!("{}", p()); // prints 25
4248-
```
4249-
4250-
There is a big difference between procs and closures: procs may only be called once. This
4251-
will error when we try to compile:
4252-
4253-
```{rust,ignore}
4254-
let x = 5i;
4255-
4256-
let p = proc() { x * x };
4257-
println!("{}", p());
4258-
println!("{}", p()); // error: use of moved value `p`
4259-
```
4260-
4261-
This restriction is important. Procs are allowed to consume values that they
4262-
capture, and thus have to be restricted to being called once for soundness
4263-
reasons: any value consumed would be invalid on a second call.
4264-
4265-
Procs are most useful with Rust's concurrency features, and so we'll just leave
4266-
it at this for now. We'll talk about them more in the "Tasks" section of the
4267-
guide.
4240+
Rust has a second type of closure, called a **moving closure**. Moving
4241+
closures are indicated using the `move` keyword (e.g., `move || x *
4242+
x`). The difference between a moving closure and an ordinary closure
4243+
is that a moving closure always takes ownership of all variables that
4244+
it uses. Ordinary closures, in contrast, just create a reference into
4245+
the enclosing stack frame. Moving closures are most useful with Rust's
4246+
concurrency features, and so we'll just leave it at this for
4247+
now. We'll talk about them more in the "Tasks" section of the guide.
42684248

42694249
## Accepting closures as arguments
42704250

@@ -5231,28 +5211,30 @@ concurrency libraries can be written for Rust to help in specific scenarios.
52315211
Here's an example of creating a task:
52325212

52335213
```{rust}
5234-
spawn(proc() {
5214+
spawn(move || {
52355215
println!("Hello from a task!");
52365216
});
52375217
```
52385218

5239-
The `spawn` function takes a proc as an argument, and runs that proc in a new
5240-
task. A proc takes ownership of its entire environment, and so any variables
5241-
that you use inside the proc will not be usable afterward:
5219+
The `spawn` function takes a closure as an argument, and runs that
5220+
closure in a new task. Typically, you will want to use a moving
5221+
closure, so that the closure takes ownership of any variables that it
5222+
touches. This implies that those variables are not usable from the
5223+
parent task after the child task is spawned:
52425224

52435225
```{rust,ignore}
52445226
let mut x = vec![1i, 2i, 3i];
52455227
5246-
spawn(proc() {
5228+
spawn(move || {
52475229
println!("The value of x[0] is: {}", x[0]);
52485230
});
52495231
52505232
println!("The value of x[0] is: {}", x[0]); // error: use of moved value: `x`
52515233
```
52525234

5253-
`x` is now owned by the proc, and so we can't use it anymore. Many other
5254-
languages would let us do this, but it's not safe to do so. Rust's borrow
5255-
checker catches the error.
5235+
`x` is now owned by the closure, and so we can't use it anymore. Many
5236+
other languages would let us do this, but it's not safe to do
5237+
so. Rust's borrow checker catches the error.
52565238

52575239
If tasks were only able to capture these values, they wouldn't be very useful.
52585240
Luckily, tasks can communicate with each other through **channel**s. Channels
@@ -5261,7 +5243,7 @@ work like this:
52615243
```{rust}
52625244
let (tx, rx) = channel();
52635245
5264-
spawn(proc() {
5246+
spawn(move || {
52655247
tx.send("Hello from a task!".to_string());
52665248
});
52675249
@@ -5281,7 +5263,7 @@ If you want to send messages to the task as well, create two channels!
52815263
let (tx1, rx1) = channel();
52825264
let (tx2, rx2) = channel();
52835265
5284-
spawn(proc() {
5266+
spawn(move || {
52855267
tx1.send("Hello from a task!".to_string());
52865268
let message = rx2.recv();
52875269
println!("{}", message);
@@ -5293,8 +5275,9 @@ println!("{}", message);
52935275
tx2.send("Goodbye from main!".to_string());
52945276
```
52955277

5296-
The proc has one sending end and one receiving end, and the main task has one
5297-
of each as well. Now they can talk back and forth in whatever way they wish.
5278+
The closure has one sending end and one receiving end, and the main
5279+
task has one of each as well. Now they can talk back and forth in
5280+
whatever way they wish.
52985281

52995282
Notice as well that because `Sender` and `Receiver` are generic, while you can
53005283
pass any kind of information through the channel, the ends are strongly typed.
@@ -5310,34 +5293,34 @@ a useful thing to use:
53105293
```{rust}
53115294
use std::sync::Future;
53125295
5313-
let mut delayed_value = Future::spawn(proc() {
5296+
let mut delayed_value = Future::spawn(move || {
53145297
// just return anything for examples' sake
53155298
53165299
12345i
53175300
});
53185301
println!("value = {}", delayed_value.get());
53195302
```
53205303

5321-
Calling `Future::spawn` works just like `spawn()`: it takes a proc. In this
5322-
case, though, you don't need to mess with the channel: just have the proc
5323-
return the value.
5304+
Calling `Future::spawn` works just like `spawn()`: it takes a
5305+
closure. In this case, though, you don't need to mess with the
5306+
channel: just have the closure return the value.
53245307

53255308
`Future::spawn` will return a value which we can bind with `let`. It needs
53265309
to be mutable, because once the value is computed, it saves a copy of the
53275310
value, and if it were immutable, it couldn't update itself.
53285311

5329-
The proc will go on processing in the background, and when we need the final
5330-
value, we can call `get()` on it. This will block until the result is done,
5331-
but if it's finished computing in the background, we'll just get the value
5332-
immediately.
5312+
The future will go on processing in the background, and when we need
5313+
the final value, we can call `get()` on it. This will block until the
5314+
result is done, but if it's finished computing in the background,
5315+
we'll just get the value immediately.
53335316

53345317
## Success and failure
53355318

53365319
Tasks don't always succeed, they can also panic. A task that wishes to panic
53375320
can call the `panic!` macro, passing a message:
53385321

53395322
```{rust}
5340-
spawn(proc() {
5323+
spawn(move || {
53415324
panic!("Nope.");
53425325
});
53435326
```
@@ -5349,7 +5332,7 @@ notify other tasks that it has panicked. We can do this with `task::try`:
53495332
use std::task;
53505333
use std::rand;
53515334
5352-
let result = task::try(proc() {
5335+
let result = task::try(move || {
53535336
if rand::random() {
53545337
println!("OK");
53555338
} else {

src/doc/intro.md

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -391,26 +391,29 @@ Here's an example of a concurrent Rust program:
391391
```{rust}
392392
fn main() {
393393
for _ in range(0u, 10u) {
394-
spawn(proc() {
394+
spawn(move || {
395395
println!("Hello, world!");
396396
});
397397
}
398398
}
399399
```
400400

401-
This program creates ten threads, who all print `Hello, world!`. The `spawn`
402-
function takes one argument, a `proc`. 'proc' is short for 'procedure,' and is
403-
a form of closure. This closure is executed in a new thread, created by `spawn`
404-
itself.
405-
406-
One common form of problem in concurrent programs is a 'data race.' This occurs
407-
when two different threads attempt to access the same location in memory in a
408-
non-synchronized way, where at least one of them is a write. If one thread is
409-
attempting to read, and one thread is attempting to write, you cannot be sure
410-
that your data will not be corrupted. Note the first half of that requirement:
411-
two threads that attempt to access the same location in memory. Rust's
412-
ownership model can track which pointers own which memory locations, which
413-
solves this problem.
401+
This program creates ten threads, who all print `Hello, world!`. The
402+
`spawn` function takes one argument, a closure, indicated by the
403+
double bars `||`. (The `move` keyword indicates that the closure takes
404+
ownership of any data it uses; we'll have more on the significance of
405+
this shortly.) This closure is executed in a new thread created by
406+
`spawn`.
407+
408+
One common form of problem in concurrent programs is a 'data race.'
409+
This occurs when two different threads attempt to access the same
410+
location in memory in a non-synchronized way, where at least one of
411+
them is a write. If one thread is attempting to read, and one thread
412+
is attempting to write, you cannot be sure that your data will not be
413+
corrupted. Note the first half of that requirement: two threads that
414+
attempt to access the same location in memory. Rust's ownership model
415+
can track which pointers own which memory locations, which solves this
416+
problem.
414417

415418
Let's see an example. This Rust code will not compile:
416419

@@ -419,7 +422,7 @@ fn main() {
419422
let mut numbers = vec![1i, 2i, 3i];
420423
421424
for i in range(0u, 3u) {
422-
spawn(proc() {
425+
spawn(move || {
423426
for j in range(0, 3) { numbers[j] += 1 }
424427
});
425428
}
@@ -432,20 +435,25 @@ It gives us this error:
432435
6:71 error: capture of moved value: `numbers`
433436
for j in range(0, 3) { numbers[j] += 1 }
434437
^~~~~~~
435-
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()?)
436-
spawn(proc() {
438+
7:50 note: `numbers` moved into closure environment here
439+
spawn(move || {
437440
for j in range(0, 3) { numbers[j] += 1 }
438441
});
439442
6:79 error: cannot assign to immutable dereference (dereference is implicit, due to indexing)
440443
for j in range(0, 3) { numbers[j] += 1 }
441444
^~~~~~~~~~~~~~~
442445
```
443446

444-
It mentions that "numbers moved into closure environment". Because we referred
445-
to `numbers` inside of our `proc`, and we create three `proc`s, we would have
446-
three references. Rust detects this and gives us the error: we claim that
447-
`numbers` has ownership, but our code tries to make three owners. This may
448-
cause a safety problem, so Rust disallows it.
447+
It mentions that "numbers moved into closure environment". Because we
448+
declared the closure as a moving closure, and it referred to
449+
`numbers`, the closure will try to take ownership of the vector. But
450+
the closure itself is created in a loop, and hence we will actually
451+
create three closures, one for every iteration of the loop. This means
452+
that all three of those closures would try to own `numbers`, which is
453+
impossible -- `numbers` must have just one owner. Rust detects this
454+
and gives us the error: we claim that `numbers` has ownership, but our
455+
code tries to make three owners. This may cause a safety problem, so
456+
Rust disallows it.
449457

450458
What to do here? Rust has two types that helps us: `Arc<T>` and `Mutex<T>`.
451459
"Arc" stands for "atomically reference counted." In other words, an Arc will
@@ -468,7 +476,7 @@ fn main() {
468476
469477
for i in range(0u, 3u) {
470478
let number = numbers.clone();
471-
spawn(proc() {
479+
spawn(move || {
472480
let mut array = number.lock();
473481
474482
(*array)[i] += 1;
@@ -528,7 +536,7 @@ fn main() {
528536
let vec = vec![1i, 2, 3];
529537
530538
for i in range(1u, 3) {
531-
spawn(proc() {
539+
spawn(move || {
532540
println!("{}", vec[i]);
533541
});
534542
}

src/doc/reference.md

Lines changed: 12 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -187,19 +187,18 @@ grammar as double-quoted strings. Other tokens have exact rules given.
187187

188188
<p id="keyword-table-marker"></p>
189189

190-
| | | | | |
191-
|----------|----------|----------|----------|--------|
192-
| abstract | alignof | as | be | box |
193-
| break | const | continue | crate | do |
194-
| else | enum | extern | false | final |
195-
| fn | for | if | impl | in |
196-
| let | loop | match | mod | move |
197-
| mut | offsetof | once | override | priv |
198-
| proc | pub | pure | ref | return |
199-
| sizeof | static | self | struct | super |
200-
| true | trait | type | typeof | unsafe |
201-
| unsized | use | virtual | where | while |
202-
| yield | | | | |
190+
| | | | | |
191+
|----------|----------|----------|----------|---------|
192+
| abstract | alignof | as | be | box |
193+
| break | const | continue | crate | do |
194+
| else | enum | extern | false | final |
195+
| fn | for | if | impl | in |
196+
| let | loop | match | mod | move |
197+
| mut | offsetof | once | override | priv |
198+
| pub | pure | ref | return | sizeof |
199+
| static | self | struct | super | true |
200+
| trait | type | typeof | unsafe | unsized |
201+
| use | virtual | where | while | yield |
203202

204203

205204
Each of these keywords has special meaning in its grammar, and all of them are
@@ -3842,8 +3841,6 @@ x = bo(5,7);
38423841
```{.ebnf .notation}
38433842
closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|'
38443843
[ ':' bound-list ] [ '->' type ]
3845-
procedure_type := 'proc' [ '<' lifetime-list '>' ] '(' arg-list ')'
3846-
[ ':' bound-list ] [ '->' type ]
38473844
lifetime-list := lifetime | lifetime ',' lifetime-list
38483845
arg-list := ident ':' type | ident ':' type ',' arg-list
38493846
bound-list := bound | bound '+' bound-list
@@ -3852,8 +3849,6 @@ bound := path | lifetime
38523849

38533850
The type of a closure mapping an input of type `A` to an output of type `B` is
38543851
`|A| -> B`. A closure with no arguments or return values has type `||`.
3855-
Similarly, a procedure mapping `A` to `B` is `proc(A) -> B` and a no-argument
3856-
and no-return value closure has type `proc()`.
38573852

38583853
An example of creating and calling a closure:
38593854

@@ -3876,30 +3871,6 @@ call_closure(closure_no_args, closure_args);
38763871

38773872
```
38783873

3879-
Unlike closures, procedures may only be invoked once, but own their
3880-
environment, and are allowed to move out of their environment. Procedures are
3881-
allocated on the heap (unlike closures). An example of creating and calling a
3882-
procedure:
3883-
3884-
```rust
3885-
let string = "Hello".to_string();
3886-
3887-
// Creates a new procedure, passing it to the `spawn` function.
3888-
spawn(proc() {
3889-
println!("{} world!", string);
3890-
});
3891-
3892-
// the variable `string` has been moved into the previous procedure, so it is
3893-
// no longer usable.
3894-
3895-
3896-
// Create an invoke a procedure. Note that the procedure is *moved* when
3897-
// invoked, so it cannot be invoked again.
3898-
let f = proc(n: int) { n + 22 };
3899-
println!("answer: {}", f(20));
3900-
3901-
```
3902-
39033874
### Object types
39043875

39053876
Every trait item (see [traits](#traits)) defines a type with the same name as

0 commit comments

Comments
 (0)