[swift-evolution] [Pitch] Limit Implicit Capture
Haravikk
swift-evolution at haravikk.me
Mon Mar 14 05:56:54 CDT 2016
I think I’m in favour of something along these lines, though personally I think the better solution is to simply eliminate implicit capture for closures and local functions, and instead provide a @capture attribute to re-enable current behaviour (and to avoid breaking code). This way developers are encouraged to either opt-in to the implicit capture behaviour, or declare a capture list, with the latter being preferred as it can more clearly declare what you need and in what capacity.
That said I think that do { … } blocks should retain implicit capture, as they’re really just a sub-section of your code, even if in some ways they can be thought of as a closure that automatically executes.
> On 14 Mar 2016, at 02:12, 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?
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
More information about the swift-evolution
mailing list