diff --git a/active/0063-upvar-capture-inference.md b/active/0063-upvar-capture-inference.md index 68159c639a2..9b0bfbcdd84 100644 --- a/active/0063-upvar-capture-inference.md +++ b/active/0063-upvar-capture-inference.md @@ -4,7 +4,7 @@ # 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 @@ -12,7 +12,7 @@ Having to specify `ref` and the capture mode for each unboxed closure is inconve 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 @@ -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 int>()` will be `fn foo 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.