Comparing types

Overview

I am trying to compare an array of types with an another array of types

Questions

  1. Why doesn't following code doesn't compile? Comparing the type t1 == t2 compiles ok but [t1] == [t2] doesn't compile.
  2. How can I compare an array of types with another array of types?
  3. Is iterating over them the only option?

Code

class Car {}
class Bike {}

let c = Car()
let b = Bike()

let t1 = type(of: c)
let t2 = type(of: b)

print(t1 == t2) // compiles ok
print([t1] == [t2]) // Type 'Car.Type' cannot conform to 'Equatable'

Conformance of Array to Equatable requires its Element to also conform to Equatable. At the time of this writing, metatypes cannot conform to protocols and their == operator is implemented as a special case by essentially wrapping the metatype into ObjectIdentifier. You can achieve a similar result by creating a wrapper type around your metatype and conform it to Equatable (and even Hashable) by using ObjectIdentifier.

3 Likes

BTW, it's not unique to types:

(1, 2) == (3, 4)        // ✅
[(1, 2)] == [(3, 4)]    // 🛑

You could make another special case for array of types:

extension [Any.Type] {
    static func == (lhs: Self, rhs: Self) -> Bool {
        if lhs.count != rhs.count { return false }
        for i in 0 ..< lhs.count {
            if lhs[i] != rhs[i] { return false }
        }
        return true
    }
}

print([t1] == [t2])     // ✅

or as an equivalent global function:

func == (lhs: [Any.Type], rhs: [Any.Type]) -> Bool {
    if lhs.count != rhs.count { return false }
    for i in 0 ..< lhs.count {
        if lhs[i] != rhs[i] { return false }
    }
    return true
}

Ditto for tuples:

func == <T: Equatable, R: Equatable> (lhs: [(T, R)], rhs: [(T, R)]) -> Bool {
    if lhs.count != rhs.count { return false }
    for i in 0 ..< lhs.count {
        if lhs[i] != rhs[i] { return false }
    }
    return true
}
4 Likes

There is an overload of elementsEqual which allows you to supply your own equivalence function.

extension Sequence where Element == Any.Type {
  static func == (sequence0: Self, sequence1: some Sequence<Element>) -> Bool {
    sequence0.elementsEqual(sequence1, by: ==)
  }
}

func == <each Element>(
  _ type0: (repeat (each Element).Type),
  _ type1: (repeat (each Element).Type)
) -> Bool {
  for types in repeat (each type0, each type1) {
    guard types.0 == types.1 else { return false }
  }
  return true
}

extension Sequence {
  static func == <each Element_Element>(
    types0: Self,
    types1: some Sequence<(repeat (each Element_Element).Type)>,
  ) -> Bool
  where Element == (repeat (each Element_Element).Type) {
    types0.elementsEqual(types1, by: ==)
  }
}
3 Likes

@technogen @tera @Danny Thanks a lot!!! Was very helpful and also thanks for the explanation why it didn't work.

I will add an extension and solve by my use case.

2 Likes