[swift-evolution] Pitch: only allow capture of inout parameters in @noescape closures
Dave Abrahams
dabrahams at apple.com
Thu Jan 28 16:19:47 CST 2016
on Thu Jan 28 2016, Joe Groff <swift-evolution at swift.org> wrote:
> I think the time has come for us to limit the implicit capture of
> 'inout' parameters to @noescape closures. In the early days before
> @noescape, we designed a semantics for capturing "inout" parameters
> that attempted to balance the constraints on inout with the usability
> of higher-order functions. Inout parameters don't pass a first-class
> reference as in other languages, but instead provide a limited lease
> to mutate a property for the duration of a call; this means closures
> can't extend the lifetime of that lease, so closures instead capture
> the local mutable copy of the inout parameter. This gives the expected
> behavior as long as closures over an inout parameter never escape
> their original scope, but leads to surprises as soon as those closures
> escape. This unintuitive behavior has made several "Swift gotchas"
> lists. Now that we can explicitly mark closures as not escaping, I
> think we should prevent 'inout' parameters from being implicitly
> captured by escapable closures. There are several ways we can still
> support today's behavior:
>
> - Encourage people to write the local copy themselves, if that's what they want:
>
> func foo(inout x: Int) {
> var localX = x; defer { x = localX }
>
> // Asynchronously mutate localX, then wait for it to finish
> dispatch_async { mutate(&localX) }
> dispatch_sync {}
> }
+1
As the author of the current semantics, I can say with confidence that
if we'd had @noescape at our disposal originally we would never have
done this.
> - You can explicitly capture an immutable copy:
>
> func foo(inout x: Int) {
> // We don't need to mutate or observe mutations on x in the async job
> dispatch_async {[x] in doStuffWithoutMutating(x) }
> }
>
> and/or we could introduce a new explicit capture kind for the current behavior:
>
> func foo(inout x: Int) {
> // Explicitly capture the 'inout' mutable shadow copy of x
> dispatch_async {[inout x] in mutate(&x) }
> dispatch_sync { }
> }
-1. Let's not complicate the language for this rare case.
> Making it explicit should make the behavior less surprising when it
> occurs. We should able to provide fixits to migrate code that relies
> on the current behavior as well. What do you all think?
>
> -Joe
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
--
-Dave
More information about the swift-evolution
mailing list