Can we match identity using `switch`?

I think I did a mistake and didn't want to write "the object" but "an NSObject", but the main point didn't change much: an object is always a reference type, but can have value semantics. e.g.

final class MyReference {
    let identifier: Int
    let name: String
    init(...) { ... }
}

This object has value semantics, and it's substitutable with any other instance with the same identifier and name values. There is a point to be made that this type should really be a struct, but I think there is a separate discussion to be made on this.

I disagree that this conformance to Equatable is correct. It's certainly doable, but unless these "other states" are only metadata and not relevant to how the object is used, then it breaks the semantic requirements of the protocol.

From the Equatable docs:

Equality implies substitutability—any two instances that compare equally can be used interchangeably in any code that depends on their values. To maintain substitutability, the == operator should take into account all visible aspects of an Equatable type. Exposing nonvalue aspects of Equatable types other than class identity is discouraged, and any that are exposed should be explicitly pointed out in documentation.

and

Equality is Separate From Identity

The identity of a class instance is not part of an instance’s value. Consider a class called IntegerRef that wraps an integer value. Here’s the definition for IntegerRef and the == function that makes it conform to Equatable:

class IntegerRef: Equatable {
   let value: Int
   init(_ value: Int) {
       self.value = value
   }

   static func == (lhs: IntegerRef, rhs: IntegerRef) -> Bool {
       return lhs.value == rhs.value
   }
}

The implementation of the == function returns the same value whether its two arguments are the same instance or are two different instances with the same integer stored in their value properties. For example:

let a = IntegerRef(100)
let b = IntegerRef(100)

print(a == a, a == b, separator: ", ")
// Prints "true, true"

Class instance identity, on the other hand, is compared using the triple-equals identical-to operator (===). For example:

let c = a
print(c === a, c === b, separator: ", ")
// Prints "true, false"
1 Like

True objects that are immutable have value semantics, forgot about that when I respond. Well I said I disagree with you as long there is no support for factory init for one specific reason. The example that I mentioned is currently using Equatable to identity an object by the same identifier even though the internal states can and will mutate as needed but a pair of two objects will still considered be the same because only the identifier is playing the main role for comparison. In fact this is actually the same as identity, more or less. If I wanted a similar behavior to UIColor which returns only unique and shared identities I could drop the Equatable protocol and start using a factory initializer to ensure that each identity is always unique regardless required dependencies (which is the deal breaker in my case). However this is completely a different topic on it's own and off-topic to this thread.

That's a part I disagree with. If, by re-using the MyReference type I defined above I implement Equatable like you suggest:

extension MyReference: Equatable {
    static func == (lhs: MyReference, rhs: MyReference) -> Bool {
        return lhs.identifier == rhs.identifier
    }
}

but you have something like

func populateView(with ref: MyReference) {
    view.titleLabel.text = ref.name
}

then the two objects are not "substitutable" anymore, and the Equatable implementation is against its semantic requirements.
That's why the docs say

To maintain substitutability, the == operator should take into account all visible aspects of an Equatable type.

1 Like

To resolve the issue with Equatable I'd need factory init for classes so only unique instances are returned.

To be honest the main issue in my case is not Equatable protocol in particular but rather Hashable which requires Equatable. Ideally I would want to have something like this:

SortedSet<MyHashableAndComparableUniqueRef>