> On Aug 5, 2016, at 12:59 PM, Kevin Ballard via swift-evolution
> <[email protected]> wrote:
>
> If all you want to do is get the localized description, then you can just say
> `(error as NSError).localizedDescription`.
Just ‘error.localizedDescription’ works now. That was part of SE-0112.
- Doug
>
> -Kevin
>
> On Fri, Aug 5, 2016, at 02:59 AM, Jean-Daniel Dupas wrote:
>>
>>> Le 5 août 2016 à 05:12, Kevin Ballard via swift-evolution
>>> <[email protected] <mailto:[email protected]>> a écrit :
>>>
>>> With NSError, you must check the domain before trying to interpret the
>>> code, or else your code is buggy and will behave incorrectly when receiving
>>> an unexpected error.
>>
>> You must check before interpreting the code, but you don’t have to interpret
>> the code to do something useful with an NSError.
>>
>> I think what Jon is looking for is ‘LocalizedError’ and ‘CustomNSError’.
>> Is there any guarantee that casting an NSError into a CustomNSError or
>> LocalizedError will always succeed ?
>>
>>> 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.
>>>
>>> So previously you might have code that looks like
>>>
>>> func handleError(error: NSError) {
>>> switch error.domain {
>>> case NSCocoaErrorDomain where error.code == NSFileNoSuchFileError:
>>> let path = error.userInfo[NSFilePathErrorKey] as? String
>>> // handle error for path
>>> case NSURLErrorDomain where error.code == NSURLErrorTimedOut:
>>> let url = error.userInfo[NSURLErrorKey] as? NSURL
>>> // handle error for url
>>> default:
>>> // generic handling of other errors
>>> }
>>> }
>>>
>>> And now you'd write that like
>>>
>>> func handleError(error: Error) {
>>> switch error {
>>> case let error as CocoaError where error.code == .fileNoSuchFileError:
>>> let path = error.filePath
>>> // handle error for path
>>> case let error as URLError where error.code == .timedOut:
>>> let url = error.failingURL
>>> // handle error for url
>>> default:
>>> // generic handling of other errors
>>> }
>>> }
>>>
>>> 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.
>>>
>>> And if you don't actually care about any of the user info properties, then
>>> the new version is much simpler than the old:
>>>
>>> func handleError(error: Error) {
>>> switch error {
>>> case CocoaError.fileNoSuchFileError:
>>> // handle error
>>> case URLError.timedOut:
>>> // handle error
>>> default:
>>> // generic handling of other errors
>>> }
>>> }
>>>
>>> It's similar to checking the code without the domain in the old style,
>>> except now it checks the domain automatically, so you still can't
>>> accidentally interpret an error's code in the wrong domain.
>>>
>>> -Kevin Ballard
>>>
>>> On Thu, Aug 4, 2016, at 11:00 AM, Jon Shier via swift-evolution wrote:
>>>> Doug:
>>>> 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.
>>>>
>>>>
>>>>
>>>> Jon
>>>>
>>>>
>>>>> On Aug 2, 2016, at 5:36 PM, Douglas Gregor <[email protected]
>>>>> <mailto:[email protected]>> wrote:
>>>>>
>>>>>
>>>>>> On Aug 2, 2016, at 2:19 PM, Jon Shier <[email protected]
>>>>>> <mailto:[email protected]>> wrote:
>>>>>>
>>>>>> 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?
>>>>>
>>>>> 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.
>>>>>
>>>>>> 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?
>>>>>
>>>>> 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.
>>>>>
>>>>> - Doug
>>>>>
>>>>>
>>>>>>
>>>>>>
>>>>>> Jon
>>>>>>
>>>>>>> On Aug 2, 2016, at 4:20 PM, Douglas Gregor <[email protected]
>>>>>>> <mailto:[email protected]>> wrote:
>>>>>>>
>>>>>>>>
>>>>>>>> On Aug 2, 2016, at 10:30 AM, Jon Shier via swift-evolution
>>>>>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>>>>>>
>>>>>>>> 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.
>>>>>>>
>>>>>>> The rename was part of the proposal, in bullet #5 of the proposed
>>>>>>> solution (which, amusing, pastes as bullet #1 below):
>>>>>>>
>>>>>>> Rename ErrorProtocol to Error: once we've completed the bridging story,
>>>>>>> Error becomes the primary way to work with error types in Swift, and
>>>>>>> the value type to which NSError is bridged:
>>>>>>>
>>>>>>> func handleError(_ error: Error, userInteractionPermitted: Bool)
>>>>>>>
>>>>>>>
>>>>>>>> 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?) -> 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?
>>>>>>>
>>>>>>> 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:
>>>>>>>
>>>>>>> extension CKError {
>>>>>>> /// Retrieve partial error results associated by item ID.
>>>>>>> public var partialErrorsByItemID: [NSObject : Error]? {
>>>>>>> return userInfo[CKPartialErrorsByItemIDKey] as? [NSObject : Error]
>>>>>>> }
>>>>>>>
>>>>>>> /// The original CKRecord object that you used as the basis for
>>>>>>> /// making your changes.
>>>>>>> public var ancestorRecord: CKRecord? {
>>>>>>> return userInfo[CKRecordChangedErrorAncestorRecordKey] as? CKRecord
>>>>>>> }
>>>>>>>
>>>>>>> /// The CKRecord object that was found on the server. Use this
>>>>>>> /// record as the basis for merging your changes.
>>>>>>> public var serverRecord: CKRecord? {
>>>>>>> return userInfo[CKRecordChangedErrorServerRecordKey] as? CKRecord
>>>>>>> }
>>>>>>>
>>>>>>> /// The CKRecord object that you tried to save. This record is based
>>>>>>> /// on the record in the CKRecordChangedErrorAncestorRecordKey key
>>>>>>> /// but contains the additional changes you made.
>>>>>>> public var clientRecord: CKRecord? {
>>>>>>> return userInfo[CKRecordChangedErrorClientRecordKey] as? CKRecord
>>>>>>> }
>>>>>>>
>>>>>>> /// The number of seconds after which you may retry a request. This
>>>>>>> /// key may be included in an error of type
>>>>>>> /// `CKErrorServiceUnavailable` or `CKErrorRequestRateLimited`.
>>>>>>> public var retryAfterSeconds: Double? {
>>>>>>> return userInfo[CKErrorRetryAfterKey] as? Double
>>>>>>> }
>>>>>>> }
>>>>>>> - Doug
>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Jon Shier
>>>>>>>>
>>>>>>>>
>>>>>>>>> On Jul 12, 2016, at 8:44 AM, Shawn Erickson via swift-evolution
>>>>>>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>>>>>>>
>>>>>>>>> Thanks for the effort on the proposal and discussion and thanks to
>>>>>>>>> those working in the implementation.
>>>>>>>>>
>>>>>>>>> -Shawn
>>>>>>>>> On Tue, Jul 12, 2016 at 12:25 AM Charles Srstka via swift-evolution
>>>>>>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>>>>>>> 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.
>>>>>>>>>
>>>>>>>>> Thanks!
>>>>>>>>>
>>>>>>>>> Charles
>>>>>>>>>
>>>>>>>>> > On Jul 11, 2016, at 11:19 PM, Chris Lattner via swift-evolution
>>>>>>>>> > <[email protected] <mailto:[email protected]>>
>>>>>>>>> > wrote:
>>>>>>>>> >
>>>>>>>>> > Proposal Link:
>>>>>>>>> > https://github.com/apple/swift-evolution/blob/master/proposals/0112-nserror-bridging.md
>>>>>>>>> >
>>>>>>>>> > <https://github.com/apple/swift-evolution/blob/master/proposals/0112-nserror-bridging.md>
>>>>>>>>> >
>>>>>>>>> > The review of "SE-0112: Improved NSError Bridging" ran from June 30
>>>>>>>>> > ... July 4, 2016. The proposal has been *accepted*:
>>>>>>>>> >
>>>>>>>>> > 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. The core team requests one minor
>>>>>>>>> > renaming of "attemptRecovery(optionIndex:andThen:)" to
>>>>>>>>> > "attemptRecovery(optionIndex:resultHandler:)”. It also discussed
>>>>>>>>> > renaming CustomNSError and RecoverableError, but decided to stay
>>>>>>>>> > with those names.
>>>>>>>>> >
>>>>>>>>> > 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!
>>>>>>>>> >
>>>>>>>>> > -Chris Lattner
>>>>>>>>> > Review Manager
>>>>>>>>> >
>>>>>>>>> > _______________________________________________
>>>>>>>>> > swift-evolution mailing list
>>>>>>>>> > [email protected] <mailto:[email protected]>
>>>>>>>>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>>>> > <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
>>>>>>>>> <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
>>>>>>>>> <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
>>>>>>>> <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
>>>> <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
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution