Skip to content

Instantly share code, notes, and snippets.

@allevato
Created April 6, 2022 03:43
Show Gist options
  • Save allevato/e657394c82a687a78bb8bc8d9ffd59ce to your computer and use it in GitHub Desktop.
Save allevato/e657394c82a687a78bb8bc8d9ffd59ce to your computer and use it in GitHub Desktop.
How to compare two Anys for equality in Swift
/// Returns a Boolean value indicating whether the two arguments are equal according to their
/// conformance to `Equatable`.
///
/// If `lhs` and `rhs` are the same type and that type conforms to ``Equatable``, then this function
/// returns the result of evaluating `==` on those values. Otherwise (if the values are different
/// types, or the same type but the type does not conform to `Equatable`), this function returns
/// false.
func areValuesEqual(_ lhs: Any, _ rhs: Any) -> Bool {
func isOpenedValueEqual<LHS>(to openedLHS: LHS) -> Bool {
let equatable = ExistentialOperations<LHS>.self as? ExistentialEquatable.Type
return equatable?.areValuesEqual(lhs, rhs) ?? false
}
return _openExistential(lhs, do: isOpenedValueEqual(to:))
}
/// A host for operations involving an opened existential.
///
/// This type cannot be instantiated and has no operations of its own. It is meant to be extended
/// with conditional conformances based on the conformances implemented by `Value`. Then, when this
/// type is specialized inside functions passed to `_openExistential`, `Value` refers to the
/// concrete type of the opened value. Therefore, operations on the concrete `Value` type can be
/// invoked indirectly through those conditional conformances.
private enum ExistentialOperations<Value> {}
/// Provides an operation to test if two existential values are equal.
private protocol ExistentialEquatable {
/// Returns true if and only if and `lhs` and `rhs` are the same type and are equal.
static func areValuesEqual(_ lhs: Any,_ rhs: Any) -> Bool
}
extension ExistentialOperations: ExistentialEquatable where Value: Equatable {
fileprivate static func areValuesEqual(_ lhs: Any,_ rhs: Any) -> Bool {
guard let lhsCast = lhs as? Value, let rhsCast = rhs as? Value else {
return false
}
return lhsCast == rhsCast
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment