<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">Le 5 août 2016 à 05:12, Kevin Ballard via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; a écrit :</div><br class="Apple-interchange-newline"><div class=""><div class=""><div class="">With NSError, you&nbsp;<i class="">must</i>&nbsp;check the domain before trying to interpret the code, or else your code is buggy and will behave incorrectly when receiving an unexpected error.&nbsp;</div></div></div></blockquote><div><br class=""></div><div>You must check before interpreting the code, but you don’t have to interpret the code to do something useful with an NSError.&nbsp;</div><div><br class=""></div><div>I think what Jon is looking for is ‘<span style="font-family: Menlo; font-size: 11px;" class="">LocalizedError’</span>&nbsp;and&nbsp;<span style="font-family: Menlo; font-size: 11px;" class="">‘CustomNSError’</span>.</div><div>Is there any guarantee that casting an NSError into a CustomNSError or LocalizedError will always succeed ?</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div class="">With SE-0112, instead of checking the domain, you check if the Error can be casted to the particular error type that represents the domain. There is a one-to-one correspondence between domains and the new error types. For example, NSCocoaErrorDomain is represented by CocoaError, NSURLErrorDomain is URLError, etc.<br class=""></div><div class=""><br class=""></div><div class="">So previously you might have code that looks like<br class=""></div><div class=""><br class=""></div><div class="">func handleError(error: NSError) {<br class=""></div><div class="">&nbsp; &nbsp; switch error.domain {<br class=""></div><div class="">&nbsp; &nbsp; case NSCocoaErrorDomain where error.code == NSFileNoSuchFileError:<br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; let path = error.userInfo[NSFilePathErrorKey] as? String</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; // handle error for path<br class=""></div><div class="">&nbsp; &nbsp; case NSURLErrorDomain where error.code == NSURLErrorTimedOut:<br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; let url = error.userInfo[NSURLErrorKey] as? NSURL<br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; // handle error for url<br class=""></div><div class="">&nbsp; &nbsp; default:</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; // generic handling of other errors<br class=""></div><div class="">&nbsp; &nbsp; }<br class=""></div><div class="">}<br class=""></div><div class=""><br class=""></div><div class="">And now you'd write that like<br class=""></div><div class=""><br class=""></div><div class="">func handleError(error: Error) {<br class=""></div><div class="">&nbsp; &nbsp; switch error {<br class=""></div><div class="">&nbsp; &nbsp; case let error as CocoaError where error.code == .fileNoSuchFileError:<br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; let path = error.filePath</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; // handle error for path<br class=""></div><div class="">&nbsp; &nbsp; case let error as URLError where error.code == .timedOut:<br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; let url = error.failingURL<br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; // handle error for url<br class=""></div><div class="">&nbsp; &nbsp; default:<br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; // generic handling of other errors<br class=""></div><div class="">&nbsp; &nbsp; }<br class=""></div><div class="">}<br class=""></div><div class=""><br class=""></div><div class="">It's the same basic structure, except now you get strong typing, you can't possibly forget to check the domain (which is a surprisingly common bug I see in a lot of code), and you get convenient accessors for the values stored in the user info.<br class=""></div><div class=""><br class=""></div><div class="">And if you don't actually care about any of the user info properties, then the new version is much simpler than the old:<br class=""></div><div class=""><br class=""></div><div class="">func handleError(error: Error) {<br class=""></div><div class="">&nbsp; &nbsp; switch error {<br class=""></div><div class="">&nbsp; &nbsp; case CocoaError.fileNoSuchFileError:<br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; // handle error<br class=""></div><div class="">&nbsp; &nbsp; case URLError.timedOut:<br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; // handle error<br class=""></div><div class="">&nbsp; &nbsp; default:<br class=""></div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; // generic handling of other errors<br class=""></div><div class="">&nbsp; &nbsp; }<br class=""></div><div class="">}<br class=""></div><div class=""><br class=""></div><div class="">It's similar to checking the code without the domain in the old style, except now it checks the domain automatically, so you&nbsp;<i class="">still</i>&nbsp;can't accidentally interpret an error's code in the wrong domain.</div><div class=""><br class=""></div><div class="">-Kevin Ballard</div><div class=""><br class=""></div><div class="">On Thu, Aug 4, 2016, at 11:00 AM, Jon Shier via swift-evolution wrote:<br class=""></div><blockquote type="cite" class=""><div class="">Doug:<br class=""></div><div class=""><span class="" style="white-space: pre;"></span>Thanks for indulging me so far, I think I’ve almost got it. Prior to this, using NSError, I could just look at the relevant properties of the error if I needed to see what type it was. Network errors had different codes from CloudKit errors, POSIX errors were underlying FileManager errors. A bit complex due to the undocumented nature of so many of these errors, but I could ignore any aspect of the error I didn’t care about. Now, however, it seems I must always care about what types of errors come out of various methods, as I’ll need to cast to the appropriate types to get useful information. For example, how would you handle the CloudKit errors I mentioned before? It seems to me like I would need to, at the point where I need to extract useful information, do a switch on various casts. First, try casting to CKError, then to CocoaError (?), and then likely produce a fatalError if there’s an unexpected type. Or is Error guaranteed to always cast to something useful? I’ve read the proposal a few times now and it looks like a lot of casting is going to be required, I’m mostly curious about the recommended patterns, especially for asynchronous calls that don’t go through throw/catch.&nbsp;<br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Jon<br class=""></div><div class=""><br class=""></div><div class=""><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Aug 2, 2016, at 5:36 PM, Douglas Gregor &lt;<a href="mailto:dgregor@apple.com" class="">dgregor@apple.com</a>&gt; wrote:<br class=""></div><div class=""><br class=""></div><div class=""><div class="" style="word-wrap: break-word; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Aug 2, 2016, at 2:19 PM, Jon Shier &lt;<a href="mailto:jon@jonshier.com" class="">jon@jonshier.com</a>&gt; wrote:<br class=""></div><div class=""><br class=""></div><div class=""><div class="" style="word-wrap: break-word; -webkit-line-break: after-white-space;"><span class="" style="white-space: pre;"></span>Thanks Doug. I missed the rename, as earlier points still referred to ErrorProtocol. In regards to the CloudKit errors, I appreciate the strongly typed CKError, but why not have the methods return that type directly?<br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">Generally speaking, Cocoa only uses NSError—not specific subclasses or NSError or other error types—because errors can occur at many different places in the stack and be propagated up. A CloudKit operation could fail because of some problem detected in a different error domain—say, the general Cocoa error domain or URLError domain—and that non-CloudKit error would get passed through immediately. So, if you were assuming that every error you get here had to be in the CloudKit error domain, I believe your code was already incorrect. It is *possible* that CloudKit translates/wraps all other errors, but that would be odd for a Cocoa framework.<br class=""></div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-line-break: after-white-space;">Every usage of these methods is going to require such a cast, so why require it in the first place? I don’t understand what advantage erasing the strongly type error that was just created has when the developer will just have to bring it right back. Or is this just a first implementation?<br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">There was never a strongly-typed error, and in most Cocoa cases there shouldn’t be one because NSError covers all error domains, by design.<br class=""></div><div class=""><br class=""></div><div class=""><span class="" style="white-space: pre;"></span>- Doug<br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Jon<br class=""></div><div class=""><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Aug 2, 2016, at 4:20 PM, Douglas Gregor &lt;<a href="mailto:dgregor@apple.com" class="">dgregor@apple.com</a>&gt; wrote:<br class=""></div><div class=""><br class=""></div><div class=""><div class=""><blockquote type="cite" class=""><div class=""><div class=""><br class=""></div><div class="">On Aug 2, 2016, at 10:30 AM, Jon Shier via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:<br class=""></div></div><div class=""><br class=""></div><div class=""><div class="" style="word-wrap: break-word; -webkit-line-break: after-white-space;"><div class=""><span class="" style="white-space: pre;"></span>I’m not sure where to put such feedback, but the ErrorProtocol to Error rename that accompanied the implementation of this proposal is very, very painful. It completely eliminates the very useful ability to embed an associated Error type inside other types, as those types now conflict with the protocol. Also, was this rename accompanied by an evolution proposal? It seems like the change was just made when this proposal was implemented.<br class=""></div></div></div></blockquote><div class=""><br class=""></div><div class="">The rename was part of the proposal, in bullet #5 of the proposed solution (which, amusing, pastes as bullet #1 below):<br class=""></div><div class=""><br class=""></div><div class=""><ol class="" style="padding-left: 2em; margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"><li class="" style="margin-top: 0.25em;"><p class="" style="margin-top: 16px; margin-bottom: 16px;">Rename&nbsp;<code class="" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">ErrorProtocol</code>&nbsp;to&nbsp;<code class="" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">Error</code>: once we've completed the bridging story,&nbsp;<code class="" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">Error</code>&nbsp;becomes the primary way to work with error types in Swift, and the value type to which&nbsp;<code class="" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">NSError</code>&nbsp;is bridged:<br class=""></p><div class="" style="margin-bottom: 16px;"><pre class="" style="font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; word-wrap: normal; padding: 16px; overflow: auto; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal;"><span class="colour" style="color: rgb(167, 29, 93);">func</span> <span class="colour" style="color: rgb(121, 93, 163);">handleError</span>(<span class="colour" style="color: rgb(121, 93, 163);">_</span> <span class="">error</span>: Error, userInteractionPermitted: <span class="colour" style="color: rgb(0, 134, 179);">Bool</span>)<br class=""></pre></div></li></ol><div class=""><br class=""></div></div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-line-break: after-white-space;"><div class=""><span class="" style="white-space: pre;"></span>Also, the adoption of this proposal by the Cocoa(Touch) frameworks as seen in Xcode 8 beta 4 has made asynchronous error handling quite a bit more arduous. For example, the CKDatabase method fetch(withRecordID recordID: CKRecordID, completionHandler: (CKRecord?, Error?) -&gt; Void) returns an `Error` now, meaning I have to cast to the specific `CKError` type to get useful information out of it. Is this just an unfortunate first effort that will be fixed, or is this the expected form of these sorts of APIs after this proposal?<br class=""></div></div></div></blockquote><div class=""><br class=""></div><div class="">Prior to this proposal, you would have had to check the domain against CKErrorDomain anyway to determine whether you’re looking at a CloudKit error (vs. some other error that is passing through CloudKit), so error bridging shouldn’t actually be adding any work here—although it might be making explicit work that was already done or should have been done. Once you have casted to CKError, you now have typed accessors for information in the error:<br class=""></div><div class=""><br class=""></div><div class=""><div class="">extension CKError {<br class=""></div><div class="">&nbsp; /// Retrieve partial error results associated by item ID.<br class=""></div><div class="">&nbsp; public var partialErrorsByItemID: [NSObject : Error]? {<br class=""></div><div class="">&nbsp; &nbsp; return userInfo[CKPartialErrorsByItemIDKey] as? [NSObject : Error]<br class=""></div><div class="">&nbsp; }<br class=""></div><div class=""><br class=""></div><div class="">&nbsp; /// The original CKRecord object that you used as the basis for<br class=""></div><div class="">&nbsp; /// making your changes.<br class=""></div><div class="">&nbsp; public var ancestorRecord: CKRecord? {<br class=""></div><div class="">&nbsp; &nbsp; return userInfo[CKRecordChangedErrorAncestorRecordKey] as? CKRecord<br class=""></div><div class="">&nbsp; }<br class=""></div><div class=""><br class=""></div><div class="">&nbsp; /// The CKRecord object that was found on the server. Use this<br class=""></div><div class="">&nbsp; /// record as the basis for merging your changes.<br class=""></div><div class="">&nbsp; public var serverRecord: CKRecord? {<br class=""></div><div class="">&nbsp; &nbsp; return userInfo[CKRecordChangedErrorServerRecordKey] as? CKRecord<br class=""></div><div class="">&nbsp; }<br class=""></div><div class=""><br class=""></div><div class="">&nbsp; /// The CKRecord object that you tried to save. This record is based<br class=""></div><div class="">&nbsp; /// on the record in the CKRecordChangedErrorAncestorRecordKey key<br class=""></div><div class="">&nbsp; /// but contains the additional changes you made.<br class=""></div><div class="">&nbsp; public var clientRecord: CKRecord? {<br class=""></div><div class="">&nbsp; &nbsp; return userInfo[CKRecordChangedErrorClientRecordKey] as? CKRecord<br class=""></div><div class="">&nbsp; }<br class=""></div><div class=""><br class=""></div><div class="">&nbsp; /// The number of seconds after which you may retry a request. This<br class=""></div><div class="">&nbsp; /// key may be included in an error of type<br class=""></div><div class="">&nbsp; /// `CKErrorServiceUnavailable` or `CKErrorRequestRateLimited`.<br class=""></div><div class="">&nbsp; public var retryAfterSeconds: Double? {<br class=""></div><div class="">&nbsp; &nbsp; return userInfo[CKErrorRetryAfterKey] as? Double<br class=""></div><div class="">&nbsp; }<br class=""></div><div class="">}<br class=""></div></div><div class=""><span class="" style="white-space: pre;"></span>- Doug<br class=""></div></div><div class=""><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Jon Shier<br class=""></div><div class=""><span class="" style="white-space: pre;"></span><br class=""></div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Jul 12, 2016, at 8:44 AM, Shawn Erickson via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:<br class=""></div><div class=""><br class=""></div><div class=""><div class="">Thanks for the effort on the proposal and discussion and thanks to those working in the implementation.<br class=""></div><div class=""><br class=""></div><div class="">-Shawn<br class=""></div><div defang_data-gmailquote="yes" class=""><div dir="ltr" class="">On Tue, Jul 12, 2016 at 12:25 AM Charles Srstka via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:<br class=""></div><blockquote defang_data-gmailquote="yes" class="" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div class="">Wow, thanks! I’m delighted that Apple found this improvement to be worth inclusion in Swift 3. This will truly make the language much nicer to use with the Cocoa frameworks.<br class=""></div><div class=""><br class=""></div><div class="">Thanks!<br class=""></div><div class=""><br class=""></div><div class="">Charles<br class=""></div><div class=""><br class=""></div><div class="">&gt; On Jul 11, 2016, at 11:19 PM, Chris Lattner via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:<br class=""></div><div class="">&gt;<br class=""></div><div class="">&gt; Proposal Link:<span class="">&nbsp;</span><a href="https://github.com/apple/swift-evolution/blob/master/proposals/0112-nserror-bridging.md" class="">https://github.com/apple/swift-evolution/blob/master/proposals/0112-nserror-bridging.md</a><br class=""></div><div class="">&gt;<br class=""></div><div class="">&gt; The review of "SE-0112: Improved NSError Bridging" ran from June 30 ... July 4, 2016. The proposal has been *accepted*:<br class=""></div><div class="">&gt;<br class=""></div><div class="">&gt; The community and core team agree that this proposal is a huge step forward that enriches the experience working with and extending the Cocoa NSError model in Swift.&nbsp; The core team requests one minor renaming of "attemptRecovery(optionIndex:andThen:)" to "attemptRecovery(optionIndex:resultHandler:)”.&nbsp; It also discussed renaming CustomNSError and RecoverableError, but decided to stay with those names.<br class=""></div><div class="">&gt;<br class=""></div><div class="">&gt; Thank you to Doug Gregor and Charles Srstka for driving this discussion forward, and for Doug Gregor taking the charge on the implementation effort to make this happen for Swift 3!<br class=""></div><div class="">&gt;<br class=""></div><div class="">&gt; -Chris Lattner<br class=""></div><div class="">&gt; Review Manager<br class=""></div><div class="">&gt;<br class=""></div><div class="">&gt; _______________________________________________<br class=""></div><div class="">&gt; swift-evolution mailing list<br class=""></div><div class="">&gt;<span class="">&nbsp;</span><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""></div><div class="">&gt;<span class="">&nbsp;</span><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div><div class=""><br class=""></div><div class="">_______________________________________________<br class=""></div><div class="">swift-evolution mailing list<br class=""></div><div class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""></div><div class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><div class="">_______________________________________________<br class=""></div><div class="">swift-evolution mailing list<br class=""></div><div class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""></div><div class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></div></blockquote></div><div class=""><br class=""></div></div><div class="">_______________________________________________<br class=""></div><div class="">swift-evolution mailing list<br class=""></div><div class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""></div><div class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></div></blockquote></div></div></blockquote></div></div></div></div></blockquote></div></div></div></blockquote></div></div><div class=""><u class="">_______________________________________________</u><br class=""></div><div class="">swift-evolution mailing list<br class=""></div><div class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""></div><div class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote><div class=""><br class=""></div></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></blockquote></div><div class=""><br class=""></div></body></html>