Skip to content

Commit

Permalink
Replace uses of proc with move per the weekly meeting
Browse files Browse the repository at this point in the history
  • Loading branch information
pcwalton committed Sep 19, 2014
1 parent 5ed7761 commit 53d713b
Showing 1 changed file with 6 additions and 8 deletions.
14 changes: 6 additions & 8 deletions active/0063-upvar-capture-inference.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

# Summary

The `||` unboxed closure form should be split into two forms—`||` for nonescaping closures and `proc()` for escaping closures—and the capture clauses and self type specifiers should be removed.
The `||` unboxed closure form should be split into two forms—`||` for nonescaping closures and `move ||` for escaping closures—and the capture clauses and self type specifiers should be removed.

# Motivation

Having to specify `ref` and the capture mode for each unboxed closure is inconvenient (see Rust PR rust-lang/rust#16610). It would be more convenient for the programmer if, the type of the closure and the modes of the upvars could be inferred. This also eliminates the "line-noise" syntaxes like `|&:|`, which are arguably unsightly.

Not all knobs can be removed, however: the programmer must manually specify whether each closure is escaping or nonescaping. To see this, observe that no sensible default for the closure `|| (*x).clone()` exists: if the function is nonescaping, it's a closure that returns a copy of `x` every time but does not move `x` into it; if the function is escaping, it's a that returns a copy of `x` and takes ownership of `x`.

Therefore, we need two forms: one for *nonescaping* closures and one for *escaping* closures. Nonescaping closures are the commonest, so they get the `||` syntax that we have today, while the `proc()` syntax that we use today for task spawning can be repurposed for escaping closures.
Therefore, we need two forms: one for *nonescaping* closures and one for *escaping* closures. Nonescaping closures are the commonest, so they get the `||` syntax that we have today, and a new `move ||` syntax will be introduced for escaping closures.

# Detailed design

Expand All @@ -28,25 +28,23 @@ The trait that the unboxed closure implements is `FnOnce` if any variables were

The `ref` prefix for unboxed closures is removed, since it is now essentially implied.

The `proc()` syntax is repurposed for unboxed closures. The value returned by a `proc()` implements `FnOnce`, `FnMut`, or `Fn`, as determined above; thus, for example, `proc(x: int, y) x + y` produces an unboxed closure that implements the `Fn(int, int) -> int` trait (and thus the `FnOnce(int, int) -> int` trait by inheritance). Free variables referenced by a `proc` are always captured by value.

As a transitionary measure, we can keep the leading `:` inside the `||` for unboxed closures, and require `proc(self, ...)` to get the unboxed version.
We introduce a new grammar production, `move ||`. The value returned by a `move ||` implements `FnOnce`, `FnMut`, or `Fn`, as determined above; thus, for example, `move |x: int, y| x + y` produces an unboxed closure that implements the `Fn(int, int) -> int` trait (and thus the `FnOnce(int, int) -> int` trait by inheritance). Free variables referenced by a `move ||` closure are always captured by value.

In the trait reference grammar, we will change the `|&:|` sugar to `Fn()`, the `|&mut:|` sugar to `FnMut()`, and the `|:|` sugar to `FnOnce()`. Thus what was before written `fn foo<F:|&mut: int, int| -> int>()` will be `fn foo<F:FnMut(int, int) -> int>()`.

It is important to note that the trait reference syntax and closure construction syntax are purposefully distinct. This is because either the `||` form or the `proc()` form can construct any of `FnOnce`, `FnMut`, or `Fn` closures.
It is important to note that the trait reference syntax and closure construction syntax are purposefully distinct. This is because either the `||` form or the `move ||` form can construct any of `FnOnce`, `FnMut`, or `Fn` closures.

# Drawbacks

1. Having two syntaxes for closures could be seen as unfortunate.

2. The `proc` keyword is somewhat random.
2. `move` becomes a keyword.

# Alternatives

1. Keep the status quo: `|:|`/`|&mut:`/`|&:|` are the only ways to create unboxed closures, and `ref` must be used to get by-reference upvars.

2. Use some syntax other than `proc()` for escaping closures.
2. Use some syntax other than `move ||` for escaping closures.

3. Keep the `|:|`/`|&mut:`/`|&:|` syntax only for trait reference sugar.

Expand Down

1 comment on commit 53d713b

@engstad
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The word "move" is used a lot in code-bases. For instance -- in every game that implements some kind of actor, you will probably see some kind of move() method. Rust has already stolen the word "crate", let us not steal more words from the game industry!

Please sign in to comment.