Suppose I have:
protocol MyError: Error, Equatable {
var errorDispalyTitle: String { get }
var errorDisplayMessage: String { get }
}
enum ContentState {
case .loading
case .error(any MyError)
case .contentLoaded
}
If i were to implement Equatable in ContentState so I can compare during unit tests I end up with a problem because I have to compare two any MyError types which are boxed and might be of two different underlying types.
extension ContentState: Equatable {
static func == (lhs: ContentState, rhs: ContentState) -> Bool {
switch (lhs, rhs) {
case (.loading, .loading):
return true
case (.contentLoaded, .contentLoaded):
return true
case (.error(let lhsError), .error(let rhsError)):
// TODO: have to compare if both underlying types are match and then if they are equal in value
default:
return false
}
}
}
How do I do this?
I tried lifting the generic from the existential type there to the type (e.g. ContentState<Error: MyError>) which lets it compile when implementing equatable as it knows how to infer the type, but the problem is for whichever class uses that enum it doesnt matter which type is receiving of it, only that is any type of it, and if I don't implement the any existential it starts requiring the generic to be propagated up the chain.
You can write a wrapper that wraps an Equatable, and wrap the LHS and RHS errors before comparing.
// resembling a similar behaviour to AnyHashable...
class AnyEquatable: Equatable {
let value: Any
private let equals: (Any) -> Bool
init<E: Equatable>(_ value: E) {
self.value = value
self.equals = { type(of: $0) == type(of: value) && $0 as? E == value }
}
static func == (lhs: AnyEquatable, rhs: AnyEquatable) -> Bool {
lhs.equals(rhs.value)
}
}
Then in your switch you can do:
case (.error(let lhsError), .error(let rhsError)):
return AnyEquatable(lhsError) == AnyEquatable(rhsError)
Note that if MyError inherits from Hashable instead of Equatable, you can use the builtin AnyHashable instead of writing your own AnyEquatable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With