Another Dude
Another Dude

Reputation: 1452

Swift - Can I make a protocol Hashable?

I have written a simple protocol Data :

public protocol Data {
    var state: [String: Any] { get set }    
    var objectId: String? { get set }    
}

public extension Data {
    var objectId: String? {
        get {
            return self.state["objectId"] as? String
        }
        set {
            self.state["objectId"] = newValue
        }
    }
}

This way, I have created several types conforming to it:

public struct Person: Data {
    public var state: [String : Any]
}
public struct Car: Data {
    public var state: [String : Any]
}
// ...

Now what I want to do is to make each of these types Hashable, the problem is that I need to write this code in every type:

extension Car Hashable {
    public static func == (lhs: Car, rhs: Car) -> Bool {
        return lhs.objectId == rhs.objectId
    }        
    public func hash(into hasher: inout Hasher) {
        hasher.combine(self.objectId ?? "")
    }    
}
// ...

What I want to know is if it is possible to generically declare Data as Hashable from its objectId. As I am using a protocol, I couldn't find a way to do so.

Thank you for your help.

Upvotes: 2

Views: 2989

Answers (1)

gcharita
gcharita

Reputation: 8327

As @Leo Dabus mentioned in his comment, you should probably use another name for your protocol due to native Foundation.Data type existence.

Either way, using the following code you can implement Hashable protocol into your Data protocol:

public protocol Data: Hashable {
    var state: [String: Any] { get set }
    var objectId: String? { get set }
}

public extension Data {
    var objectId: String? {
        get {
            return self.state["objectId"] as? String
        }
        set {
            self.state["objectId"] = newValue
        }
    }
    
    static func == (lhs: Self, rhs: Self) -> Bool {
        return lhs.objectId == rhs.objectId
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(self.objectId ?? "")
    }
}

Although this will have as a side effect that protocol Data can only be used as a generic constraint because it has Self or associated type requirements:

enter image description here

Meaning that you can now on use the Data protocol like this:

func myFunc<T: Data>(data: T) {
    
}

Upvotes: 4

Related Questions