Realistically, there are still going to be large changes to Swift.
I expect conditional conformances, for example, to basically transform huge amounts of Swift code, including the standard library. Karl > > On Jul 15, 2016 at 7:53 PM, <Charles Srstka via swift-evolution > (mailto:[email protected])> wrote: > > > > Won’t that involve source breakage, though? The grammar for calling > asynchronous APIs will have changed. > > Charles > > > On Jul 14, 2016, at 11:54 PM, Chris Lattner <[email protected] > > (mailto:[email protected])> wrote: > > > > When/if we get an async/await like feature, of course we’ll try to pull > > completion handlers automatically into the model. We can do that post swift > > 3. > > > > -Chris > > > >> On Jul 14, 2016, at 3:30 PM, Charles Srstka via swift-evolution > >> <[email protected] (mailto:[email protected])> wrote: > >> > >> Right, but since this would affect the Obj-C importer and thus would be a > >> source-breaking change, it would probably not be possible anymore after > >> Swift 3. > >> > >> Charles > >> > >>> On Jul 14, 2016, at 4:57 PM, Dan Stenmark <[email protected] > >>> (mailto:[email protected])> wrote: > >>> > >>> I’d say it’s a little premature to be talking about this; the team has > >>> made it very clear that the discussion on Native Concurrency in Swift > >>> won’t begin for another couple months. > >>> > >>> Dan > >>> > >>>> On Jul 14, 2016, at 10:54 AM, Charles Srstka via swift-evolution > >>>> <[email protected] (mailto:[email protected])> wrote: > >>>> > >>>> I know it’s late, but I was wondering what the community thought of > >>>> this: > >>>> > >>>> MOTIVATION: > >>>> > >>>> With the acceptance of SE-0112, the error handling picture looks much > >>>> stronger for Swift 3, but there is still one area of awkwardness > >>>> remaining, in the area of returns from asynchronous methods. > >>>> Specifically, many asynchronous APIs in the Cocoa framework are declared > >>>> like this: > >>>> > >>>> - (void)doSomethingWithFoo: (Foo *)foo completionHandler: (void (^)(Bar > >>>> * _Nullable, NSError * _Nullable))completionHandler; > >>>> > >>>> This will get imported into Swift as something like this: > >>>> > >>>> func doSomething(foo: Foo, completionHandler: (Bar?, Error?) -> ()) > >>>> > >>>> The intention of this API is that either the operation will succeed, > >>>> and something will be passed in the Bar parameter, and the error will be > >>>> nil, or else the operation will fail, and then the error parameter will > >>>> be populated while the Bar parameter is nil. However, this intention is > >>>> not expressed in the API, since the syntax leaves the possibility that > >>>> both parameters could be nil, or that they could both be non-nil. This > >>>> forces the developer to do needless and repetitive checks against a case > >>>> which in practice shouldn’t occur, as below: > >>>> > >>>> doSomething(foo: foo) { bar, error in > >>>> if let bar = bar { > >>>> // handle success case > >>>> } else if let error = error { > >>>> self.handleError(error) > >>>> } else { > >>>> self.handleError(NSCocoaError.FileReadUnknownError) > >>>> } > >>>> } > >>>> > >>>> This results in the dreaded “untested code.” > >>>> > >>>> Note that while it is possible that the developer could simply > >>>> force-unwrap error in the failure case, this leaves the programs open to > >>>> crashes in the case where a misbehaved API forgets to populate the error > >>>> on failure, whereas some kind of default error would be more > >>>> appropriate. The do/try/catch mechanism works around this by returning a > >>>> generic _NilError in cases where this occurs. > >>>> > >>>> PROPOSED SOLUTION: > >>>> > >>>> Since the pattern for an async API that returns an error in the Cocoa > >>>> APIs is very similar to the pattern for a synchronous one, we can handle > >>>> it in a very similar way. To do this, we introduce a new Result enum > >>>> type. We then bridge asynchronous Cocoa APIs to return this Result type > >>>> instead of optional values. This more clearly expresses to the user the > >>>> intent of the API. > >>>> > >>>> In addition to clarifying many Cocoa interfaces, this will provide a > >>>> standard format for asynchronous APIs that return errors, opening the > >>>> way for these APIs to be seamlessly integrated into future asynchronous > >>>> features added to Swift 4 and beyond, in a way that could seamlessly > >>>> interact with the do/try/catch feature as well. > >>>> > >>>> DETAILED DESIGN: > >>>> > >>>> 1. We introduce a Result type, which looks like this: > >>>> > >>>> enum Result<T> { > >>>> case success(T) > >>>> case error(Error) > >>>> } > >>>> > >>>> 2. Methods that return one parameter asynchronously with an error are > >>>> bridged like this: > >>>> > >>>> func doSomething(foo: Foo, completionHandler: (Result<Bar>) -> ()) > >>>> > >>>> and are used like this: > >>>> > >>>> doSomething(foo: foo) { result in > >>>> switch result { > >>>> case let .success(bar): > >>>> // handle success > >>>> case let .error(error): > >>>> self.handleError(error) > >>>> } > >>>> } > >>>> > >>>> 3. Methods that return multiple parameters asynchronously with an error > >>>> are bridged using a tuple: > >>>> > >>>> func doSomething(foo: Foo, completionHandler: (Result<(Bar, Baz)>) -> > >>>> ()) > >>>> > >>>> and are used like this: > >>>> > >>>> doSomething(foo: foo) { result in > >>>> switch result { > >>>> case let .success(bar, baz): > >>>> // handle success > >>>> case let .error(error): > >>>> self.handleError(error) > >>>> } > >>>> } > >>>> > >>>> 4. Methods that return only an error and nothing else are bridged as > >>>> they are currently, with the exception of bridging NSError to Error as > >>>> in SE-0112: > >>>> > >>>> func doSomething(foo: Foo, completionHandler: (Error?) -> ()) > >>>> > >>>> and are used as they currently are: > >>>> > >>>> doSomething(foo: foo) { error in > >>>> if let error = error { > >>>> // handle error > >>>> } else { > >>>> // handle success > >>>> } > >>>> } > >>>> > >>>> 5. For the case in part 2, the bridge works much like the do/try/catch > >>>> mechanism. If the first parameter is non-nil, it is returned inside the > >>>> .success case. If it is nil, then the error is returned inside the > >>>> .error case if it is non-nil, and otherwise _NilError is returned in the > >>>> .error case. > >>>> > >>>> 6. For the case in part 3, in which there are multiple return values, > >>>> the same pattern is followed, with the exception that we introduce a new > >>>> Objective-C annotation. I am provisionally naming this annotation > >>>> NS_REQUIRED_RETURN_VALUE, but the developer team can of course rename > >>>> this annotation to whatever they find appropriate. All parameters > >>>> annotated with NS_REQUIRED RETURN_VALUE will be required to be non-nil > >>>> in order to avoid triggering the error case. Parameters not annotated > >>>> with NS_REQUIRED RETURN_VALUE will be inserted into the tuple as > >>>> optionals. If there are no parameters annotated with NS_REQUIRED > >>>> RETURN_VALUE, the first parameter will be implicitly annotated as such. > >>>> This allows asynchronous APIs to continue to return optional secondary > >>>> values if needed. > >>>> > >>>> Thus, the following API: > >>>> > >>>> - (void)doSomethingWithFoo: (Foo *)foo completionHandler: (void (^)(Bar > >>>> * _Nullable NS_REQUIRED_RETURN_VALUE, Baz * _Nullable > >>>> NS_REQUIRED_RETURN_VALUE, NSError * _Nullable))completionHandler; > >>>> > >>>> is bridged as: > >>>> > >>>> func doSomething(foo: Foo, completionHandler: (Result<(Bar, Baz)>) -> > >>>> ()) > >>>> > >>>> returning .success only if both the Bar and Baz parameters are non-nil, > >>>> whereas this API: > >>>> > >>>> - (void)doSomethingWithFoo: (Foo *)foo completionHandler: (void (^)(Bar > >>>> * _Nullable NS_REQUIRED_RETURN_VALUE, Baz * _Nullable, NSError * > >>>> _Nullable))completionHandler; > >>>> > >>>> is bridged as: > >>>> > >>>> func doSomething(foo: Foo, completionHandler: (Result<(Bar, Baz?)>) -> > >>>> ()) > >>>> > >>>> returning .success whenever the Bar parameter is nil. An API containing > >>>> no parameter annotated with NS_REQUIRED_RETURN_VALUE will be bridged the > >>>> same as above. > >>>> > >>>> FUTURE DIRECTIONS: > >>>> > >>>> In the future, an asynchronous API returning a Result could be bridged > >>>> to an async function, should those be added in the future, using the > >>>> semantics of the do/try/catch mechanism. The bridging would be additive, > >>>> similarly to how Objective-C properties declared via manually written > >>>> accessor methods can nonetheless be accessed via the dot syntax. Thus, > >>>> > >>>> func doSomething(_ completionHandler: (Result<Foo>) -> ()) > >>>> > >>>> could be used as if it were declared like this: > >>>> > >>>> async func doSomething() throws -> Foo > >>>> > >>>> and could be used like so: > >>>> > >>>> async func doSomethingBigger() { > >>>> do { > >>>> let foo = try await doSomething() > >>>> > >>>> // do something with foo > >>>> } catch { > >>>> // handle the error > >>>> } > >>>> } > >>>> > >>>> making asynchronous APIs convenient to write indeed. > >>>> > >>>> ALTERNATIVES CONSIDERED: > >>>> > >>>> Leaving the somewhat ambiguous situation as is. > >>>> > >>>> Charles > >>>> > >>>> _______________________________________________ > >>>> swift-evolution mailing list > >>>> [email protected] (mailto:[email protected]) > >>>> https://lists.swift.org/mailman/listinfo/swift-evolution > >>> > >> > >> _______________________________________________ > >> swift-evolution mailing list > >> [email protected] (mailto:[email protected]) > >> https://lists.swift.org/mailman/listinfo/swift-evolution > > > > _______________________________________________ > swift-evolution mailing list (mailto:[email protected]) > [email protected] (mailto:[email protected]) > https > (mailto:[email protected])://lists.swift.org/mailman/listinfo/swift-evolution >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
