0

I have the following I want to achieve in Swift:

I have a protocol

protocol IdProtocol {
  static var id: Int { get }
}

Now I want each implementor of this potocol to have a different value for id.

For example:

struct One: IdProtocol {}
struct Two: IdProtocol {}

Here, One will have id 0 and Two will have id 1 (or vice versa).

How can I implement this in Swift? I'd like to have this as a protocol extension so that all structs implementing IdProtocol will automatically be assigned an id. This can be done lazily.

I haven't been able to find a solution to this.

Jomy
  • 514
  • 6
  • 22

1 Answers1

1

You won't be able to create it in this way that there is a consecutive Int, starting at 0 and incrementing for each type automatically. You would have to solve all kinds of issues in a manual way.

  • Which is the implementation where the counter starts?
  • What is the counter when the compiler encounters the next implementation?
  • What happens if the compile order changes? Is this critical if the ids change each time you compile?

What you could do however is the following: use a protocol extension to define a standard implementation for id and hash the name of the type:

extension IdProtocol {
    static var id: Int {
        var hasher = Hasher()
        hasher.combine(String(describing: Self.self))
        return hasher.finalize()
    }
}

This should be enough for most cases. But it will be a (more or less) random Int for each type. Still, that id will stay constant between compiler runs (until you rename a class). And you should only run into collisions when the names collide as well.

JanMensch
  • 1,720
  • 1
  • 18
  • 27
  • To answer some of the issues: in my case, it does not matter which struct is assigned an id first. It also isn't required that these ids stay the same between compilations. The ids are used on a per-run basis, so no data is persisted between runs. So the implementation where the counter starts wouldn't really matter in my case. – Jomy Jan 27 '23 at 21:49
  • @Jomy as I said, you won't be able to automatically get this. The best you can do (without writing this unique ID feature yourself) is the above with pretty much random IDs. If you need consecutive Int IDs you would need to implement this by yourself and use some data structure to which you register all protocol implementations yourself. But then you could as well also hand out the IDs manually yourself as well. Getting this automatically would be a language feature and Swift doesn't provide that. – JanMensch Jan 28 '23 at 22:23
  • I ended up going with your hashing implementation. For performance reasons, I will prompt users using my library to overwrite the id field if they need to – Jomy Jan 29 '23 at 09:04