Synthesized Equatable and protocol-typed properties

I have a struct that contains an error property typed as Error:

struct Foo {
    var error: Error
}

I would like Foo to be Equatable and I would like to get the synthesized equatable implementation, since there are many properties on Foo. The error property is an obvious stumbling block, though. I don’t mind comparing error equality using localizedDescription, but is there a way to do it while keeping the synthesized Equatable?

The only solution I have come up with is a wrapper:

public struct AnyError {

    public let wrapped: Error

    public init(_ wrapped: Error) {
        self.wrapped = wrapped
    }
}

extension AnyError: Equatable {

    public static func == (lhs: AnyError, rhs: AnyError) -> Bool {
        return lhs.wrapped.localizedDescription == rhs.wrapped.localizedDescription
    }
}

struct Foo {
    var error: AnyError
}

Is there a better solution?

Imho yours is the correct one, if the equality of Errors is defined as that only for the sake of this model. In this case I would use a different name for the wrapper though, as AnyError seems to indicate it's okay for other purposes.

If instead you want that equality to be valid project-wide for Errors, then you should theoretically do extension Error: Equatable, which is not valid Swift. Workarounds to that are either protocol EquatableError: Error, Equatable, if you only care about errors that you define yourself, or a wrapper like you did in all cases. I would make the wrapper conform to Error though ;)

Also in general I wouldn't use AnyError as a name even in the latter case, as the Any prefix is usually used for type erasure, and it might look confusing to a reader since there are no types to erase.

1 Like