[swift-evolution] [swift-evolution-announce] [Review] SE-0112: Improved NSError Bridging

Charles Srstka cocoadev at charlessoft.com
Thu Jun 30 21:19:14 CDT 2016


> On Jun 30, 2016, at 5:36 PM, Charles Srstka via swift-evolution <swift-evolution at swift.org> wrote:
> 
>> One comment though:
>> 
>> Why is the errorDescription of LocalizedError an optional? Why would a type conform to this protocol, and then choose not to provide its only extension to ErrorProtocol?
> 
> This one’s my fault; Gregory originally had this as a non-optional and I recommended changing it, because Cocoa uses a nil value for NSLocalizedDescriptionKey to indicate that the default behavior should be used to construct the error string. In my experience, this is usually in fact what you want, and NSLocalizedFailureReasonErrorKey is a better fit for most purposes. For example, when throwing an error in an NSDocument subclass:
> 
> override func read(from data: Data, ofType typeName: String) throws {
>     let userInfo = [NSLocalizedFailureReasonErrorKey: "Something went wrong."]
>     throw NSError(domain: "Foo", code: 1, userInfo: userInfo)
> }
> 
> In the example above, the error is presented to the user as “The operation could not be completed. Something went wrong.”
> 
> However, if you fill in the localized description instead of the failure reason, like this:
> 
> override func read(from data: Data, ofType typeName: String) throws {
>     let userInfo = [NSLocalizedDescriptionKey: "Something went wrong."]
>     throw NSError(domain: "Foo", code: 1, userInfo: userInfo)
> }
> 
> The user is shown “The operation could not be completed.” with no further information.
> 
> Even when you’re reporting errors directly, the behavior is different whether you provide the localized description or omit it. With a nil description, as below:
> 
> let userInfo = [NSLocalizedFailureReasonErrorKey: "Something went wrong."]
> NSApp.presentError(NSError(domain: "Foo", code: 1, userInfo: userInfo))
> 
> The error is presented as “The operation could not be completed. Something went wrong.” By comparison, if we provide the description:
> 
> let userInfo = [NSLocalizedDescriptionKey: "Something went wrong."]
> NSApp.presentError(NSError(domain: "Foo", code: 1, userInfo: userInfo))
> 
> The error is simply reported as “Something went wrong.” This seems somewhat brusque, compared to the more polite and blow-softening behavior of the former example.
> 
> Unfortunately, I can’t think of any way for this property to return a non-optional, human-readable string to the end user while still communicating to NSError that the field should be nil, unless the default implementation can either copy the code that NSError uses to generate this value, or call through to NSError to generate it. I do notice that NSError always returns something appropriate when you call -localizedDescription on it, although it has the advantage that that method is only used to retrieve the value, not to provide it, unlike here.

Actually, looking at the proposal again, it looks like Gregory has already solved this issue. #4 under Proposed Solution mentions a “localizedDescription” property on Error/ErrorProperty, provided by Foundation, which appears to do the equivalent of calling -localizedDescription on NSError. The optional “errorDescription” property on CustomCocoaError/CustomNSError is there for bridging purposes, and localizedDescription is what you’d use to get the string for presentation. Having separate APIs for separate purposes is probably better than trying to hack two uses into the same property, honestly.

Charles

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160630/62a87c3f/attachment.html>


More information about the swift-evolution mailing list