[swift-evolution] [Proposal] Make non-escaping closures the default

John McCall rjmccall at apple.com
Thu Jun 9 18:10:40 CDT 2016


> On Jun 9, 2016, at 3:43 PM, Jordan Rose via swift-evolution <swift-evolution at swift.org> wrote:
> 
> I'm against this for library evolution reasons: if someone releases a version of their library that has a non-escaping closure and later discovers it needs to be escaping, they can't change it.
> 
> IIRC the counterpoint to this is that people were probably implicitly relying on it being non-escaping already, and that there aren't many cases where you'd want to do this anyway.

Right.  APIs are already semantically constrained in how they're allowed to use their closure arguments.  Closure arguments inject arbitrary code, with arbitrary data access, into the callee; as a rule, the caller must know how the callee intends to use the closure, or its semantics will be grossly violated.  You can't re-implement an existing API that always synchronously sub-invokes a closure to instead call the closure asynchronously or concurrently because it is completely reasonable for the caller to pass a closure that relies on being called synchronously or from at most one thread at once and/or within a fixed range of time.  For example, the closure may modify a captured local variable, or it may it use a network connection that will be closed after the API returns.  APIs that want to do this sort of thing have to reserve the right to do that (and even then, they may have binary compatibility limitations), in which case it is totally reasonable to expect them to express that in the type.

> My counter-counterpoint is that you might have some case, like dispatch_async (er, DispatchQueue.async) with a semaphore where you know the closure isn't escaping, but you need to treat it as one. Maybe that just means we need an asUnsafeEscapingClosure helper in the standard library.

I agree that it's important to have some unsafe method of dodging the restriction.  Apparently unsafeBitCast works right now, although it really shouldn't and we should come up with a better alternative.

John.

> I also think it might be useful to be able to annotate references as non-escaping (purely for performance reasons), and I can't see those being non-escaping by default. I know we don't want to block one change because of something else that might happen down the line, but still.
> 
> Jordan
> 
> 
>> On Jun 5, 2016, at 20:49, Trent Nadeau via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> https://github.com/tanadeau/swift-evolution/blob/make-noescape-default/proposals/XXXX-make-noescape-default.md <https://github.com/tanadeau/swift-evolution/blob/make-noescape-default/proposals/XXXX-make-noescape-default.md>
>> 
>> # Make non-escaping closures the default
>> 
>> * Proposal: [SE-NNNN](NNNN-name.md)
>> * Author: [Trent Nadeau](https://github.com/tanadeau <https://github.com/tanadeau>)
>> * Status: **Awaiting review**
>> * Review manager: TBD
>> 
>> ## Introduction
>> 
>> The current default of closure arguments to functions (i.e., arguments to functions that themselves have function type such as `(T) -> U`) is to be "escaping", meaning they can escape the function body such as saving it to a field in a struct or a global variable. In order to say that a closure argument cannot possibly escape the function body ("non-escaping"), the developer must explicitly add an `@noescape` annotation to the argument type.
>> 
>> This proposal switches the default to be non-escaping and requires an `@escaping` annotation if a closure argument can escape the function body. Since the escaping case can be statically detected, this annotation can be added via an error with a fixit. Other annotations that have consequences for escape semantics (e.g., `@autoclosure(escaping)`) will be altered to make use of the new `@escaping` annotation.
>> 
>> Swift-evolution threads: [Discussion thread topic for that proposal (TBD)](http://news.gmane.org/gmane.comp.lang.swift.evolution <http://news.gmane.org/gmane.comp.lang.swift.evolution>)
>> 
>> ## Motivation
>> 
>> Per Chris Lattner [on swift-evolution](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160530/019880.html <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160530/019880.html>):
>> 
>> > To provide some more details, this approach has the following advantages:
>> >
>> > - Most functional algorithms written in pure Swift will benefit because they are naturally noescape.  The core team feels that this will reduce the boilerplate involved with writing these algorithms.
>> >
>> > - The compiler has enough logic in it to provide a great QoI experience when a developer doesn’t think about escaping, and tries to escape a closure - it can provide a fixit that suggests adding @escaping.
>> >
>> > - Recent changes (to disallow escaping closures to close over an inout parameter) are pushing the language to prefer noescape closures.  noescape closures have also always been the preferred default, since they eliminate a class of retain cycle issues.
>> >
>> > - "@autoclosure(escaping)" can be simplified and standardized to "@autoclosure @escaping”
>> 
>> ## Detailed design
>> 
>> The `@noescape` annotation is removed from the language. The compiler will emit an error with a fixit to remove the annotation.
>> 
>> The compiler will emit an error if a closure argument is found to possibly escape the function body. In order to silence the warning, the developer must add, manually or via fixit, the `@escaping` annotation to the argument type.
>> 
>> The compiler's semantic analysis implementation can be simplified as the more constrained escaping case that conflicts with other attributes is now no longer the default.
>> 
>> The standard library should be changed to use the new default whenever possible by removing all uses of `@noescape` and only adding `@escaping` where the compiler detects the need.
>> 
>> ### Imported C/Objective-C APIs
>> 
>> Per the Core Team, most Cocoa closure/block parameters are escaping (e.g., delegates). As such the Clang importer will automatically add the `@escaping` annotation to closure/block parameters encountered in imported Objective-C APIs unless they are explicitly marked with the Clang `((noescape))` attribute. This will also be done with imported C APIs with function pointer or block parameters.
>> 
>> ## Impact on existing code
>> 
>> Existing code using the `@noescape` attribute will need to be migrated to remove the attribute since it will be the default. In addition, the compiler will need to detect escaping closures that are not marked with `@escaping` and create an error with a fixit to add the required attribute.
>> 
>> Uses of `@autoclosure(escaping)` must be changed to `@autoclosure @escaping`.
>> 
>> There should be few, if any, changes required for uses of Cocoa APIs as these will be mostly marked as `@escaping`, and escaping closure arguments are *more* constrained than non-escaping ones.
>> 
>> ## Future directions
>> 
>> The `@noescape(once)` annotation proposed in [SE-0073](https://github.com/apple/swift-evolution/blob/master/proposals/0073-noescape-once.md <https://github.com/apple/swift-evolution/blob/master/proposals/0073-noescape-once.md>) would, if some future version is accepted, just become `@once`.
>> 
>> ## Alternatives considered
>> 
>> Leave the `@noescape` attribute and existing semantics as they are now.
>> 
>> ## Acknowledgements
>> 
>> Thanks to Chris Lattner, **TBD**, and anyone else who reviewed and contributed to this proposal.
>> 
>> 
>> -- 
>> Trent Nadeau
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160609/69da89ef/attachment.html>


More information about the swift-evolution mailing list