Generics methods lookup doesn't work well when adopting protocols with generics clauses

I guess that I capture a bug in methods lookup or an intended behavior. Don't really now.

Consider following example:

// MARK: StorageFile.swift

// MARK: Protocols
protocol StorageHolderProtocol {
    associatedtype Key: Hashable
    associatedtype Value
    subscript (_ key: Key) -> Value? { get set }
}

protocol StorageHolderKeyStringAndValueAnyProtocol: StorageHolderProtocol where Self.Key == String, Self.Value == Any {
    func add<T>(_ entry: T)
    func get<T>(by type: T.Type) -> T?
}

private protocol StorageHolderProtocol_Private: StorageHolderProtocol {
    var store: Dictionary<Key, Value> { get set }
}

extension StorageHolderProtocol_Private {
    subscript (_ key: Key) -> Value? {
        get {
            self.store[key]
        }
        mutating set {
            self.store[key] = newValue
        }
    }
}

private protocol StorageHolderKeyStringAndValueAnyProtocol_Private: StorageHolderKeyStringAndValueAnyProtocol, StorageHolderProtocol_Private {
}

extension StorageHolderKeyStringAndValueAnyProtocol_Private {
    func typeName(some: Any) -> String {
        return (some is Any.Type) ? "\(some)" : "\(type(of: some))"
    }
    
    func add<T>(_ entry: T) {
        let key = typeName(some: T.self)
//        self.store[key] = entry
    }
    
    func get<T>(by type: T.Type) -> T? {
        let key = typeName(some: T.self)
        return self.store[key] as? T
    }
}

// MARK: Class

class MyStore: StorageHolderKeyStringAndValueAnyProtocol, StorageHolderKeyStringAndValueAnyProtocol_Private {
    var store: Dictionary<String, Any> = .init()
}
// MARK: ExampleFile.swift

class Example {
    static func example() {
        let store = MyStore()
        store. // <- doesn't show methods `.get` and `.add` in pop-up.
        store.add(SomeClass.self) // <- works.
    }
}

If class Example is defined in StorageFile.swift near MyStore, methods lookup works without hassle.

Try making
StorageHolderProtocol_Private and StorageHolderKeyStringAndValueAnyProtocol_Private
internal instead.

This structure isn’t supposed to work - in that lower-access protocols can’t provide implementations for requirements of more-public protocols.

What you wrote is basically a version of this pattern, I think: Synthesized collection conformance for simple wrappers

I don't understand why my technique doesn't work and shouldn't work.
Swift should restrict my tries in "conforming" to protocols by introducing private protocols.

As you see above, MyStore conforms to both Public and Private versions of StorageHolderKeyStringAndValueAnyProtocol protocol. So, Xcode should give me correct method lookup.

Could you describe a little bit your example? Is it a kind of Type Erasure technique? ( Actually, Box part where you wrap protocols with associated types in to classes with flatten generics parameters ).

Terms of Service

Privacy Policy

Cookie Policy