john_ryan john_ryan - 5 months ago 12
Swift Question

Implementing a default equals method for a protocol

I've been trying to implement a protocol and protocol extension that provides a default == method in swift. Something like this:

protocol NameProtocol: Equatable {
func getName() -> String
}

extension NameProtocol{}

func ==<T: NameProtocol>(lhs: T, rhs: T) -> Bool{
return lhs.getName() == rhs.getName()
}


Then a class like this:

class NamedObject: NSObject, NameProtocol {

let name: String

init(name: String) {
self.name = name
super.init()
}

func getName() -> String {
return self.name
}

}


However, the custom == method is never called:

let one = NamedObject(name: "Name")
let two = NamedObject(name: "Name")
if one == two {
NSLog("EQUAL")
}
else{
NSLog("NOT EQUAL")
}


Am I doing something wrong here?

UPDATE:

From the answers I got it looks like what i'm trying to accomplish isn't really possible. The only way to come close is to subclass (which has its obvious drawbacks). I'm going to keep a lookout for a proper solution.

Answer

Because the == operator from the superclass takes precedence over that of the protocol. And for NSObject, == means pointer equal.

If you remove the inheritance from NSObject, it works as expected:

class NamedObject: NameProtocol {

    let name: String

    init(name: String) {
        self.name = name
        super.init()
    }

    func getName() -> String {
        return self.name
    }

}

I can't find any documentation on the order of precedence when there are multiple implementations for ==. This is just my experience.


Edit: instead of defining == for the protocol, define your own base class to override NSObject's default behavior:

class MyBaseClass: NSObject {
    func getName() -> String {
        fatalError("You must override this method")
    }
}

func == (lhs: MyBaseClass, rhs: MyBaseClass) -> Bool {
    return lhs.getName() == rhs.getName()
}

class NamedObject: MyBaseClass {
    let name: String

    init(name: String) {
        self.name = name
    }

    override func getName() -> String {
        return self.name
    }
}
Comments