Auto implement Unique ID in a hashable class

3.1k views Asked by At

I create a new class that I want to be Hashable and Equatable so I can easily loop through it, a class example is below:

class MyClass: Hashable {
    var uid: Int
    var myName: String
    var myAge:Int
    var hashValue: Int {
        return self.uid
    }
    init(uid: Int, name: String, age: Int) {
        self.uid = uid
        self.myName = name
        self.myAge = age
    }
}

func ==(lhs: MyClass, rhs: MyClass) -> Bool {
    return lhs.uid == rhs.uid
}

The problem is that now I have to pass a uid when I create the class, like so:

let user1 = MyUser(uid: 1, name: "Me", age: 36)

I want to make the uid static and auto generate a new one for each object I create, like so:

let user2 = User(name: "The other guy", age: 23)

In this case the uid for user2 would be equals 2, it is just a set property it does not need to have a get as it should work completely transparent to the person using the class.

However everytime I try to change uid to be a static var or a class var I cannot make it conform with Hashable protocol

Thanks in advance

3

There are 3 answers

0
fqdn On BEST ANSWER

What I think you're going for is: (1) you'd like to have a type property that stores the next (or last) UID to vend, and (2) every time you create a User, you'd like them to automatically be assigned a UID.

Something like below would accomplish this task (note we also include a generateUid() function):

class MyClass: Hashable {
    static var nextUid = 1
    static func generateUid() -> Int {
      return nextUid++
    }

    let uid: Int
    var myName: String
    var myAge:Int
    var hashValue: Int {
        return self.uid
    }
    init(name: String, age: Int) {
        self.uid = MyClass.generateUid()
        self.myName = name
        self.myAge = age
    }
}
1
Ben G On

Not sure that's what you want, but in case the only reason you created a "uid" property was to emulate a sort of reference equality instead of value equality (which you could be, since you're using classes instead of struct), you may also want to look at :

var hashValue: Int { 
        return ObjectIdentifier(self).hashValue
    }
0
cicerocamargo On

The solution marked as right is good and right to the point. My only concern is that nextUid is a var that any other method in the class can update. If you want more secure (and even reusable) solution, you can do something like this:

class HashableIdGenerator {

    private var nextId = 0

    func generate() -> Int {
        nextId += 1
        return nextId
    }
}

class AClass: Hashable {

    private static let idGenerator = HashableIdGenerator()

    let uid: Int

    init() {
        uid = AClass.idGenerator.generate()
    }

    var hashValue: Int { return uid }

    // implement Equatable here
}