Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift - Binary operator '===' cannot be applied to two protocols [duplicate]

Tags:

swift

I'm trying to compare two protocol types using the reference comparison (===). When I do I get (where Foo is a protocol):

Binary operator '===' cannot be applied to two 'Foo' operands

I understand why == won't work without conforming to Equatable, but in this case I'm using ===, which is just an address comparison.

like image 268
Steve Kuo Avatar asked Jan 02 '16 18:01

Steve Kuo


2 Answers

Let's show the problem on declarations:

The === operator is declared for AnyObject.

public func ===(lhs: AnyObject?, rhs: AnyObject?) -> Bool

What exactly is AnyObject? AnyObject is a protocol to which all classes automatically conform.

In Swift, there are not only class types, there are also value types, e.g structs and enums. All of them can conform to protocols but structs and enums do not conform to AnyObject. Since you have Java background, the behavior of value types is similar to primitive types in Java - they are passed by value (copying) and you don't usually get a reference to them.

When you are declaring a protocol, the compiler doesn't know whether it will be adopted by classes or structs.

protocol X {}

struct A: X {}

let x1: X = A()
let x2: X = A()

// PROBLEM - we cannot compare two structs by ===
if x1 === x2 {
}

That means we have to tell the compiler that the protocol can be adopted only by classes:

protocol X: AnyObject {}

or

protocol X: class {}

Then

class A: X {}  // can be adopted only by classes

let x1: X = A()
let x2: X = A()

// NO problem
if x1 === x2 {
}
like image 195
Sulthan Avatar answered Nov 08 '22 02:11

Sulthan


=== comparator is for comparing references - since structs are value types they pass by value and do not have references. (essentially passing a struct just takes a copy)

Classes are pass by reference - the instance is stored in memory so you are able to use the === comparator.

So yes you can compare them, but you need to ensure the protocol is constrained to classes only.

e.g.

//: Playground - noun: a place where people can play

protocol Foo: class {

}

class A: Foo {

}

class B: Foo {

}

let a: Foo = A()
let b: Foo = A()
let c: Foo = B()

a === a // true
a === b // false
a !== c // true
b === c // false
c === c // true

where

struct B: Foo {

}

would fail to compile

like image 40
Oliver Atkinson Avatar answered Nov 08 '22 04:11

Oliver Atkinson