Static stored properties not supported in generic types

The earliest discussion of this is here.

I need a generic wrapper with its own unique-id space.

enum my {
    // A wrapper with its own unique-id space
    struct Wrapper <T>: Identifiable {
        let value: T
        let id   : Int = Self.uniqueID ()
              
        private static var uniqueID = UIDStore ()
                // Error: Static stored properties not supported in generic types
    }

    struct UIDStore {
        private var value: Int = 0
        mutating func callAsFunction () -> Int {
            defer {value += 1}
            return value
        }
    }
}

Currently I find myself doing this, writing a wrapper for each specific type I need.

extension my {
    // An Int wrapper with its own unique-id space
    struct IntWrapper: Identifiable {
        let value: Int
        let id   : Int = Self.uniqueID ()
        
        private static var uniqueID = UIDStore ()
    }
}

extension my {
    // A String wrapper with its own unique-id space
    struct StringWrapper: Identifiable {
        let value: String
        let id   : Int = Self.uniqueID ()
        
        private static var uniqueID = UIDStore ()
    }
}

Can anyone guide me towards an elegant solution, one that still uses the generic type parameter? :slight_smile:

Edit - PS: Want id's to be monotonically rising and be in the range 0..<N for a given type.

Declare a static computed property instead, and have it erase the generic parameter into an Any.Type, which you can then wrap in a struct that conforms to Hashable so it can be used as a key in a dictionary that’s stored in a global variable.

1 Like

Piggybacking on that: use ObjectIdentifier to hash the types.

4 Likes

Thank you, @jrose and @Slava_Pestov

I have ended up using the ObjectIdentifier (T.Type.self) as a key into a dictionary to maintain the UIDStore objects for different types.

Details
enum unique_ID {
    // A type wrapper with its own unique-id space
    struct Wrapper <T>: Identifiable {
        let value: T
        let id   : Int = Self.uniqueID
              
        private static var uniqueID: Int {
            let key = ObjectIdentifier (T.Type.self)
            if let u = uidd [key] {
                return u ()
            }
            else {
                let s = UIDStore ()
                uidd [key] = s
                return s ()
            }
        }
    }

    private class UIDStore {
        private var value: Int = 0
        func callAsFunction () -> Int {
            defer {value += 1}
            return value
        }
    }
    
    static private var uidd: [ObjectIdentifier: UIDStore] = [:]
}