[swift-evolution] [Pitch] Limit Implicit Capture
Joe Groff
jgroff at apple.com
Wed Mar 16 13:23:55 CDT 2016
> On Mar 13, 2016, at 7:12 PM, Daniel Duan via swift-evolution <swift-evolution at swift.org> wrote:
>
> I'm curious to see if anyone else has desire for this change.
>
> Currently, scopes created by functions, closures, "do {}", etc.
> implicitly capture values from their outer scopes. The only way to opt out
> this behavior is via functions defined "elsewhere":
>
> func a() { ... }
> func foo(b: () -> ()) {
> func c() { ... }
> let d = { ... }
>
> a() // nothing from foo's scope will implicitly get into a
> b() // nothing from foo's scope will implicitly get into b
>
> c() // implicitly captures values in foo
> d() // implicitly captures values in foo
> do {
> // implicitly captures values in foo
> }
> }
>
> One problem that comes with this bebavior is unintended capturing. E.g. a user
> may think they successfuly factored out some code, but a missing variable was
> satified by something with the same name from an outer scope.
>
> C++ addresses this issue by making its user explicitly indicate lambda's
> capturing behavior:
>
> [] {...} // capture nothing
> [=] {...} // capture everything by value
> [&] {...} // capture everything by reference
>
> It'd be nice if Swift can allow user to opt out the automatic capturing at
> some level. We already have the capture list syntax, reusing it for explictly
> capture in this case:
>
> func foo() {
> let a = 5
> let b = "Ziggy"
> let c = ["Weild", "Gilly"]
>
> let d: @explicit_capture () -> () = { [a, b] in
> let years = a // ok
> let artist = b // ok
> let others = c // error: implicit capture in not allowed for 'd'
> }
> }
>
>
> An alternative would be making implicit capture an opt-in feature (similar to
> C++):
>
> func foo() {
> let a = 5
> let b = "Ziggy"
> let c = ["Weild", "Gilly"]
>
> let d = { [a] in
> let years = a // ok
> let artist = b // error: implicit capture in not allowed for 'd'
> let others = c // error: implicit capture in not allowed for 'd'
> }
>
> let e: @capture_all () -> () = { [a] in
> let years = a // ok
> let artist = b // ok
> let others = c // error: implicit capture in not allowed for 'e'
> }
> }
>
> Obviously, this version would be a breaking change.
>
> I have no attchment to the syntax. Chris has brought up moving @noescape
> before variable types declaration, so putting @explicit_capture there seems
> natural.
>
> Thoughts?
I like the idea, but this seems to me like more a property of the closure literal than the function type, so the annotation belongs in the capture list. {[only a, b] in a + b } maybe (filling in your own preferred syntax for 'only').
-Joe
More information about the swift-evolution
mailing list