> On Jun 30, 2016, at 1:30 PM, Scott James Remnant via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> +1
> 
> I continually find the use of `as` for bridging between Objective-C and Swift 
> types to be confusing, since they do not have a true place in the Swift type 
> hierarchy and are not simple casts. The `catch let error as NSError` 
> construct always implies that NSError is a true type that can be thrown, and 
> this confusion gets worse in the places where NSError “leaks” out of APIs and 
> you can’t actually cleanly bridge from an ErrorProtocol anyway.

The weird and convoluted behavior of the “as” keyword is one of the uglier (and 
more error-prone) warts in the language as it currently stands. There was a 
proposal a while back to remove the bridging behavior from the “as” keyword, 
greatly simplifying its behavior, but discussion on it seems to have died down. 
I hope it can be revived once this proposal is accepted, since the need for “as 
NSError” was one of the main problems with that proposal.

> 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.

Charles

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to