When does the == operator depend on Equatable and when does it not?

I have an array of the following struct:

struct AtomCameraType
{
    var APIIdentifier: Input.HDRCamera
    var name: String

    init(...
}

That APIIdentifier, of type Input.HDRCamera, is a generated Google Protocol Buffer enum in Swift:

enum HDRCamera: SwiftProtobuf.Enum {
    typealias RawValue = Int
    case standard // = 1
    case sony // = 2
    case canon // = 3
    case panasonic // = 4
    case arri // = 5
    case jvc // = 6
    case red // = 7
    case rec2100 // = 8
    case fujifilm // = 9
    case nikon // = 10
    case proResRaw // = 11

    init() {
      self = .standard
    }

This may not conform to the Equatable protocol.

Attempts to match one of these enums against another with == works in a straight if statement, but fails when using == in firstIndex(where:.

So this works (cameraTypes is the aforementioned array of AtomCameraType):

for testType in AtomCamera.cameraTypes()  // array of struct AtomCameraType
{
    if testType.APIIdentifier == camType.APIIdentifier
    {
        debugPrint("Match found.")
    }
}

but this doesn't:

if let camIndex = AtomCamera.cameraTypes().firstIndex(where: { $0.APIIdentifier == camType.APIIdentifier })
{
    debugPrint("Match found.")
}

but finally, it works if I add rawValue:

if let camIndex = AtomCamera.cameraTypes().firstIndex(where: { $0.APIIdentifier.rawValue == camType.APIIdentifier.rawValue })
{
    // This works.
    ...
}

So it seems to me that == doesn't always need conformance to Equatable, but sometimes it does. Or is there something else going on here?

UPDATE: So, with no changes to this code, it now works. I made extensive changes in the AtomCamera object, but not to these structs or cameraTypes(). And, as you can see from the working/non-working examples (which I had in the code at the same time), they're both using the same call to cameraTypes() to fetch the array.

Returning to this issue, I looked for other firstIndex(where:) calls with similar structs and ==, and found that they worked. So I removed the ".rawValue" from this troublesome one experimentally... to find that the firstIndex now works. Baffling.

What's the protocol here? Delete this or close it, or just leave it?

1 answer

  • answered 2019-08-23 23:50 Alexander

    The == operator "doesn't need" Equatable. In fact, no function, subscript, property or operator requirement of any protocol "needs" its protocol. Being present is a requirement for the protocol, but even without the protocol, nothing prevents an == operator from being defined, no different from any other arbitrary protocol.

    I don't know what the definition of cameraTypes() is, but there is no difference between the == operator used in your if statement and that used in the firtIndex(where:) call. I don't know why it's exhibiting different behaviour for you.

    Your rawValue example works because the rawValue's type is Int (or some integral type, IDK the specifics of SwiftProtobuf.Enum), which is Equatable (and thus, necessarily has a == operator defined).