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?
To adopt the Equatable protocol, implement the equal-to operator ( == ) as a static method of your type. The standard library provides an implementation for the not-equal-to operator ( != ) for any Equatable type, which calls the custom == function and negates its result.
In Swift, an Equatable is a protocol that allows two objects to be compared using the == operator. The hashValue is used to compare two instances. To use the hashValue , we first have to conform (associate) the type (struct, class, etc) to Hashable property.
The short answer is that we can't. Each conforming type can be Equatable (in fact both our concrete types are) but we don't have a way of checking equality at the level of the protocol since the protocol does not declare any properties.
Overview. Types that conform to the Equatable protocol can be compared for equality using the equal-to operator ( == ) or inequality using the not-equal-to operator ( != ). Most basic types in the Swift standard library conform to Equatable .
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With