[swift-evolution] [Pitch] Consistent bridging for NSErrors at the language boundary

Charles Srstka cocoadev at charlessoft.com
Sat May 14 04:39:55 CDT 2016


> On May 14, 2016, at 3:51 AM, Michael Peternell <michael.peternell at gmx.at> wrote:
> 
> For interoperability, ErrorType and NSError should be toll-free-bridged, like CFStringRef and NSString. Converting between them should be a no-op at runtime.

That would be technically infeasible without restricting ErrorType to reference types using the Objective-C runtime, which I don’t think anyone wants to do.

> I prefer runtime/ABI consistency over syntax/language consistency. MyErrorType2 should be represented as an NSError with domain @"MyErrorType2", whatever code is defined in that error type, and if you want userInfo you have to create the beast as an NSError object in the first place. I think userInfo is not visible in the Swift-enum-representation. If you want to have a Swift Error representation that includes userInfo, you'd have to either change the architecture or introduce special support on the language level (e.g. a magic `er.userInfo` of type `Dictionary<String,AnyObject>` for every `er: ErrorType` and a `er.withUserInfo(userInfo)` to add a userInfo dictionary to an error type: e.g. `MyErrorType2.fooConditionFound.withUserInfo([NSLocalizedDescriptionKey: "that was really bad"])` and maybe even a convenience method as a protocol extension like `MyErrorType.fooConditionFound.withLocalizedDescription(localizedString: "ReallyBad")`.

Adding a userInfo property to the protocol declaration (with a default implementation for those that don’t want to implement it) would solve this without any low-level hacking.

> And the key of a dictionary should really always be a String, not just an NSObject.)

I actually agree; I used [NSObject : AnyObject] since that’s what NSError’s userInfo is currently defined as. Putting [String : AnyObject] in the protocol instead would be fine, although you’d have to do a little sanity checking in the bridging to filter out non-string keys from the dictionary.

> (I know if you have something like `case SpecialError(Int)` in your ErrorType declaration, the above method does not work; you'd have to create an NSError-subclass for it. Or maybe not? Just add a "SpecialError_arg0" key to userInfo, value can be an NSNumber? There are more edge cases here but they are all solvable.)
> 
> On the other hand, I don't think that enumerations in general should support instance variables. One of the nice things for an enum is that I as a programmer can always be sure that it *is* just an enum, and nothing else. Adding iVars to enums would effectively turning enums to structs, and each time I see a switch statement I'll have to think "is this really all? or is there some stealth value attached to this enum? is every .MadeAMistake object always the same?" Keeping the inconsistency constrained to the ErrorType is much nicer than turning every enum into a struct.

Adding instance variables to enums is not necessary for this. The userInfo here can be implemented as a computed property, as it would be in enums (in classes and structs, of course, it would be up to the developer whether to make it a stored or computed property).

> There will always be rough edges when converting between two languages, that's unavoidable. Try to translate a text that contains a lot of the words "safety" and "security" into German. Good luck, they both translate to the same word. And so there also cannot be a perfectly consistent translation between ErrorType and NSError. If you want to achieve a good translation, you'd have to change the ErrorType to something different. E.g. a special language construct `def-error MyErrorType { case MadeAMistake; case RanOutOfCake }` - matching works the same as now and you have a userInfo property. And on non-objc-platforms, the NSError() name becomes unavailable and .userInfo always returns `[:]`. I'm not saying that this would be a beautiful solution; I'm saying that there is no beautiful solution to this problem.


I think that creating wrappers for both directions could work pretty well if we had a userInfo property on ErrorType/Protocol. We’ve got one going in one direction already.

Charles

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160514/9b706389/attachment.html>


More information about the swift-evolution mailing list