Hi all,
Looking for feedback on a @completionHandlerAsync
attribute.
Introduction
Add a new @completionHandlerAsync
attribute to designate a synchronous function as having an asynchronous alternative, ie. one that uses the new async
language feature (SE-0296) but otherwise provides “equivalent” functionality to the attributed function.
Motivation
As projects migrate towards the new concurrency language features, it could be helpful to both users and tooling to mark non-async and async function pairs. The presence of this attribute would enable tooling to provide functionality to assist with the migration effort:
- Output a compiler warning (and possibly fixit) for any call to an
@completionHandlerAsync
attributed function in an asynchronous context - Aid in refactorings to replace calls to completion-handler functions with their async alternatives
Proposed solution
A new function attribute @completionHandlerAsync
that takes the name of the async alternative function and (optionally) the position of the completion handler parameter, assumed to be the last parameter if not given.
@completionHandlerAsync("processImplicit(data:)")
func processImplicit(data: Data, completion: @escaping (ProcessedData) -> Void) { ... }
func processImplicit(data: Data) async -> ProcessedData { ... }
@completionHandlerAsync("processExplicit(data:)", completionHandlerIndex: 1)
func processExplicit(data: Data, completion: @escaping (ProcessedData) -> Void) { ... }
func processExplicit(data: Data) async -> ProcessedData { ... }
@completionHandlerAsync("processNonTrailing(data:)", completionHandlerIndex: 0)
func processNonTrailing(completion: @escaping (ProcessedData) -> Void, data: Data) { ... }
func processNonTrailing(data: Data) async -> ProcessedData { ... }
Detailed design
An attribute of the form @completionHandlerAsync(<name>[, completionHandlerIndex: <n>])
, permitted where:
- it’s attached to a non-
async
,Void
-returning function with at leastn - 1
parameters (wheren
is the index of the last parameter if not given), -
name
is a string literal containing the non-ambiguous compound name of the async alternative function that must be located in the same context as the attributed function, - the completion handler argument referenced by
completionHandlerIndex
is an@escaping
and non-@autoclosure
Void
-returning function type.
This attribute should be implicitly added to Objective-C completion-handler methods that are also imported as async
. See the Concurrency Interoperability with Objective-C proposal for more details on those (SE-0297).
Attributes on protocol or class methods should be inherited by their implementation and overrides. Attributing the implementation/override is an error if one is already specified by the parent, ie.
protocol MyProto {
@completionHandlerAsync("process(data:)", completionHandlerIndex: 1)
func process(data: Data, completion: (ProcessedData) -> Void)
func process(data: Data) async -> ProcessedData
}
struct MyStruct: MyProto {
@completionHandlerAsync("process(data:)", completionHandlerIndex: 1) // error
func process(data: Data, completion: (ProcessedData) -> Void) { ... }
func process(data: Data) async -> ProcessedData { ... }
}
A partial implementation of @completionHandlerAsync
has been implemented under the -enable-experimental-concurrency
flag (thanks @etcwilde). Inheriting the attribute on implementations and overrides is yet to be implemented.
Source compatibility and effect ABI
The proposed solution is purely additive and has no affect on the ABI.
Alternatives considered
Defaults
The completion handler will almost always be the last parameter of a function to take advantage of Swift’s trailing closure syntax. Given that, an implicit default seems ideal. It wouldn’t be unusual to have overloaded functions, or to want a separate async function name - hence the explicit function name.
Implicit Pairing
Instead of an attribute, the compiler could implicitly pair functions where one “looks like” the async alternative. This could never be perfect though, so could result in both spurious and missed warnings and refactorings.