[swift-evolution] [Accepted] SE-0112: Improved NSError Bridging

Charles Srstka cocoadev at charlessoft.com
Sun Aug 14 03:18:36 CDT 2016


> On Aug 14, 2016, at 2:34 AM, Jon Shier <jon at jonshier.com> wrote:
> 
> 	Sorry Charles, I should’ve been more specific. This isn’t about some other type named Error being usable, but about our doubly generic Result and other types being usable with Error as the generic error type. If we have Result defined as:
> 
> public enum Result<Value, ErrorType: Error> {
>     case success(Value)
>     case failure(ErrorType)
> }
> 
> then attempting to create the type Result<Whatever, Error> results in the error message I posted. For methods that previously returned Result<Whatever, NSError>, where the NSError is either a system error or an Alamofire one, this is something of a problem. Of course, removing the generic error type fixes this but may have an undesirable usability impact, as making Result double generic was the primary reason behind the quick upgrade between Alamofire 2 and 3. I think it’s less of a problem now, as having to enumerate all of the different expected error types is how user’s are supposed to interact with Error in the first place, but at the time it wasn’t desirable to try and force everything through ErrorProtocol for that reason. Perhaps this is a good compromise, where instead of returning all NSErrors from the framework and allowing consumers to add their own to the mix we’ll just create our own AFError type (whether enum or struct) and then anything coming back will have to be checked for that type in addition to the system types. From my testing it looks like users could still wrap everything coming in by capturing the underlying Error.

Still seems to be working well, unless I’m misunderstanding what you’re trying to do:

import Foundation

enum Result<Value, ErrorType: Error> {
    case success(Value)
    case failure(ErrorType)
}

struct MyThing {
    enum Error: Swift.Error, LocalizedError {
        case doesNotCompute
        case imSorryDave
        case mustSterilize
        case irrelevant
        case endOfLine
        
        var failureReason: String? {
            switch self {
            case .doesNotCompute:
                return "Does Not Compute! Does Not Compute! Does Not Compute!"
            case .imSorryDave:
                return "I'm sorry Dave, I'm afraid I can't do that."
            case .mustSterilize:
                return "Error! Must Sterilize! Must Steeerrrrilllliiiiiiizzzzzzeeeeeee"
            case .irrelevant:
                return "Irrelevant. Resistance is futile."
            case .endOfLine:
                return "End of Line!"
            }
        }
    }
    
    func trySomething(shouldWork: Bool, completionHandler: (Result<String, Error>) -> ()) {
        if shouldWork {
            completionHandler(.success("It worked!"))
        } else {
            completionHandler(.failure(Error.imSorryDave))
        }
    }
}

let thing = MyThing()

let completionHandler = { (result: Result<String, MyThing.Error>) in
    switch result {
    case let .success(value):
        print("returned '\(value)'")
    case let .failure(error):
        print("error: \(error.localizedDescription)")
    }
}

thing.trySomething(shouldWork: true, completionHandler: completionHandler)
thing.trySomething(shouldWork: false, completionHandler: completionHandler)

returned 'It worked!'
error: The operation couldn’t be completed. I'm sorry Dave, I'm afraid I can't do that.
Program ended with exit code: 0

Charles
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160814/3e750594/attachment.html>


More information about the swift-evolution mailing list