Search code examples
swiftprotocols

Swift: How to check if Error conforms to a protocol


Different custom errors & system errors conform to a custom protocol, in this example LoggableError. However, when trying to check the conformance of that Error to that custom protocol, Swift fails to cast or even check it (with an is-check). My class receives an Error, but cannot check if the error implements the custom protocol or not.

Example:

import Foundation

protocol LoggableError: Error {
    var message: String { get }
}

extension URLError: LoggableError {
    var message: String {
        switch code {
        case .notConnectedToInternet: return "no internet"
        default: return ""
        }
    }
}

func log(error: Error) {
    guard let error = error as? LoggableError else { // This cast fails
        return
    }
    print(error.message)
}

let error = URLError(.notConnectedToInternet)
log(error: error)

Note that when casting to URLError in that log(error:) method, the conformance is checkable & error is cast-able. 🤯 Any ideas here?


Solution

  • The problem you are seeing is caused by the fact that protocol's don't conform to themselves.

    By changing your log method to take its error type as a generic parameter rather than an Error existential, you can solve the problem, since the generic type now conforms to LoggableError, unlike the existential Error.

    func log<E: Error>(error: E) {
      guard let error = error as? LoggableError else {
        return
      }
      print(error.message)
    }
    

    Or you can use some Error as a shorthand instead of having to declare the method generic.

    func log(error: some Error) {