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

Charles Srstka cocoadev at charlessoft.com
Sun Aug 14 20:43:04 CDT 2016


> On Aug 14, 2016, at 7:04 PM, Jon Shier <jon at jonshier.com> wrote:
> 
> 	Yes, if you return a single error type it works fine. However, since Alamofire wraps the underlying networking frameworks there’s a need to return the errors returned from them as well, which are now returned as Error. In order to let these errors be returned alongside Alamofire’s errors we’d either have to get rid of the generic error and just use Error or wrap all errors in our error type. So far the least painful method seems to be just getting rid of the generic error and returning Error for everything. That way users will use the same logic they would have had to use anyway and can also provide their own error wrapper if they want. Thankfully (or unfortunately, depending on your point of view), the new pattern is to cast out the various error types, so the previous concern about having to do that is no longer an issue.

Is there something wrong with just returning a Swift.Error and using casting to catch specific errors?

import Foundation

enum Result<Value> {
    case success(Value)
    case failure(Swift.Error)
}

struct StarTrek {
    enum Error: Swift.Error, LocalizedError {
        case insufficientData
        case sheCannaTakeIt
        case warpCoreBreach(minutes: Int)
        case irrelevant
        case mustSterilize
        
        var failureReason: String? {
            switch self {
            case .insufficientData:
                return "Insufficient data. Please specify parameters."
            case .sheCannaTakeIt:
                return "She canna take it anymore, Captain!"
            case let .warpCoreBreach(minutes):
                return "Warning: Warp core breach in \(minutes) minutes."
            case .mustSterilize:
                return "Error! Must Sterilize! Must Steeerrrrilllliiiiiiizzzzzzeeeeeee"
            case .irrelevant:
                return "Irrelevant. Resistance is futile."
            }
        }
    }
    
    static func engage(warpFactor: Int) throws {
        throw Error.sheCannaTakeIt
    }
}

struct SciFi {
    enum Error: Swift.Error, LocalizedError {
        case doesNotCompute
        case imSorryDave
        case fixedPointInTime
        case gameOver
        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 .fixedPointInTime:
                return "I'm sorry, I'm so sorry."
            case .gameOver:
                return "Game over man, game over!"
            case .endOfLine:
                return "End of Line!"
            }
        }
    }
    
    static func flyThroughSpace(isStarTrek: Bool, completionHandler: (Result<String>) -> ()) {
        if isStarTrek {
            do {
                try StarTrek.engage(warpFactor: 5)
                completionHandler(.success("We have arrived at Rigel VII"))
            } catch {
                completionHandler(.failure(error))
            }
        } else {
            completionHandler(.failure(Error.imSorryDave))
        }
    }
}

let completionHandler = { (result: Result<String>) in
    switch result {
    case let .success(value):
        print("returned '\(value)'")
    case let .failure(error):
        if let starTrekError = error as? StarTrek.Error {
            print("Star Trek error: \(starTrekError.localizedDescription)")
            
            if case .sheCannaTakeIt = starTrekError {
                print("Scotty, I need more power!")
            }
        } else if let scifiError = error as? SciFi.Error {
            print("Sci fi error: \(scifiError.localizedDescription)")
            
            if scifiError == .imSorryDave {
                print("Daisy... Daaaaaaiiiiiisssssyyyyy.........")
            }
        } else {
            print("Some other error: \(error.localizedDescription)")
        }
    }
}

SciFi.flyThroughSpace(isStarTrek: true, completionHandler: completionHandler)
SciFi.flyThroughSpace(isStarTrek: false, completionHandler: completionHandler)

Star Trek error: The operation couldn’t be completed. She canna take it anymore, Captain!
Scotty, I need more power!
Sci fi error: The operation couldn’t be completed. I'm sorry Dave, I'm afraid I can't do that.
Daisy... Daaaaaaiiiiiisssssyyyyy.........
Program ended with exit code: 0

And of course, for synchronous APIs using try/catch, you can just use “catch error as StarTrek.Error” to get these.

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


More information about the swift-evolution mailing list