I'm trying to implement the ==
operator (from Equatable
) in a base class and its subclasses in Swift 3. All of the classes will only be used in Swift so I do not want to involve NSObject
or the NSCopying
protocol.
I started with a base class and a subclass:
class Base {
var x : Int
}
class Subclass : Base {
var y : String
}
Now I wanted to add Equatable
and the ==
operator to Base
. Seems simple enough. Copy the ==
operator signature from the documentation:
class Base : Equatable {
var x : Int
static func == (lhs: Base, rhs: Base) -> Bool {
return lhs.x == rhs.x
}
}
So far so good. Now for the subclass:
class Subclass : Base {
static override func == (lhs: Base, rhs: Base) -> Bool {
return true
}
}
But this results in an error:
Operator function overrides a 'final' operator function
OK. After some research (still learning Swift 3) I learn that static
can be replaced with class
to indicate the type method can be overridden.
So I attempt to change static
to class
in Base
:
class Base : Equatable {
var x : Int
class func == (lhs: Base, rhs: Base) -> Bool {
return lhs.x == rhs.x
}
}
But that results in a new error:
Operator '==' declared in non-final class 'Base' must be 'final'
Ugh. This is far more complicated than it should be.
How do I implement the Equatable
protocol and the ==
operator properly in a base class and a subclass?
After lots of research and some trial and error I finally came up with a working solution. The first step was moving the ==
operator from inside the class to the global scope. This fixed the errors about static
and final
.
For the base class this became:
func == (lhs: Base, rhs: Base) -> Bool {
return lhs.x == rhs.x
}
class Base : Equatable {
var x : Int
}
And for the subclass:
func == (lhs: Subclass, rhs: Subclass) -> Bool {
return true
}
class Subclass : Base {
var y : String
}
Now the only part left is figuring out how to call the ==
operator of the base class from the ==
operator of the subclass. This led me to the final solution:
func == (lhs: Subclass, rhs: Subclass) -> Bool {
if lhs.y == rhs.y {
if lhs as Base == rhs as Base {
return true
}
}
return false
}
That first if
statement results in a call to the ==
operator in the base class.
The final solution:
Base.swift:
func == (lhs: Base, rhs: Base) -> Bool {
return lhs.x == rhs.x
}
class Base : Equatable {
var x : Int
}
Subclass.swift:
func == (lhs: Subclass, rhs: Subclass) -> Bool {
if lhs.y == rhs.y {
if lhs as Base == rhs as Base {
return true
}
}
return false
}
class Subclass : Base {
var y : String
}