How to compare "Any" value types

The only way to do this is with a function other than == that takes a type parameter, and then compares the values if they are both of that type:

func isEqual<T: Equatable>(type: T.Type, a: Any, b: Any) -> Bool {
    guard let a = a as? T, let b = b as? T else { return false }

    return a == b
}

Now, using your variables above, you can compare them like this:

var any1: Any = 1
var any2: Any = 1

var any3: Any = "test"
var any4: Any = "test"

isEqual(type: Int.self, a: any1, b: any2)      // true
isEqual(type: Int.self, a: any2, b: any3)      // false
isEqual(type: String.self, a: any3, b: any4)   // true

To use == operator, type has to conform to Equatable protocol. Any protocol does not conform to Equatable protocol, so there is no way to compare two Any values. It's logical - Any is too broad term - values can have no 'common denominator'.

What's more, Swift doesn't allow to compare two Equatable values which have different type. E.g. both Int and String conform to Equatable but 1 == "1" does not compile. The reason for that is the declaration of == in Equatable protocol: func ==(lhs: Self, rhs: Self) -> Bool. This Self basically means that both arguments have to have the same type. It it's kind of a placeholder - in implementation for specific type, Self should be replaced with the name of this type.


You can do it like this by using AnyHashable:

func equals(_ x : Any, _ y : Any) -> Bool {
    guard x is AnyHashable else { return false }
    guard y is AnyHashable else { return false }
    return (x as! AnyHashable) == (y as! AnyHashable)
}

print("\(equals(3, 4))")        // false
print("\(equals(3, equals))")   // false
print("\(equals(3, 3))")        // true

As not every Equatable has to be Hashable, this might fail under rare circumstances.

Usually there is no reason for using above hack; but sometimes you will need it, just as sometimes AnyHashable is needed.


Aaron Rasmussen's answer can also be used as an extension, like so:

public extension Equatable {
  /// Equate two values of unknown type.
  static func equate(_ any0: Any, _ any1: Any) -> Bool {
    guard
      let equatable0 = any0 as? Self,
      let equatable1 = any1 as? Self
    else { return false }

    return equatable0 == equatable1
  }
}
final class EquatableTestCase: XCTestCase {
  func test_equate() {
    let int: Any = Int.random( in: .min...(.max) )
    let bool: Any = Bool.random()

    XCTAssertTrue( Int.equate(int, int) )
    XCTAssertTrue( .equate(bool, bool) )
    XCTAssertFalse( .equate(int, int) )

    XCTAssertTrue( AnyHashable.equate(bool, bool) )
    XCTAssertFalse( AnyHashable.equate(bool, int) )
  }
}

Tags:

Swift