Extending Swift's Dictionary to conform to Protocol that requires the use of subscript causes Linker Error

487 views Asked by At

The title says it all, but I have a protocol like:

protocol MyProtocol {
    typealias KeyType
    typealias ValueType

    subscript(key: KeyType) -> ValueType? { get set }
}

And trying to make Dictionary conform to MyProtocol like:

extension Dictionary: MyProtocol {
}

results in the Linker Error:

Undefined symbols for architecture x86_64:
"__TFVSs10Dictionarym9subscriptFQ_GSqQ0__", referenced from:
  __TTWUSs8Hashable___GVSs10DictionaryQ_Q0__18ProjectName11MyProtocolS1_FS2_m9subscriptFQQPS2_12KeyTypeGSqQS3_15ValueType_ in Searcher.o

Now, the interesting part is that if I reimplement subscript, the error goes away, but I don't know how to reimplement it without causing infinite recursion.

If instead of { get set }, the protocol requires { get } the error also goes away and the extension works as desired.

So I imagine the issue must be in the set side of things, trying to require { get mutating set } also doesn't work.

Does anyone know (a) what's going on and (b) how to make Dictionary conform to MyProtocol, without having to resort to drastic solutions like reimplementing subscript?

At first I was convinced it was a bug with Swift, but after probing it a bit, I am not so sure.

I'm using Swift 1.2

Edit: I managed to make it work by doing the following:

extension Dictionary: MyProtocol {
    subscript(key: Key) -> Value? {
        get {
            let index = self.indexForKey(key)

            if let i = index {
                return self[i].1
            }

            return nil
        }
        set {
            if let value = newValue {
                self.updateValue(value, forKey: key)
            } else {
                self.removeValueForKey(key)
            }
        }
    }
}

But re-implementing the Dictionary's subscript really doesn't seem like a good idea to me.

Edit 2: Clearer Question.

Edit 3: Tried the same code out in Swift 2.0 and it still doesn't work. Curiously the linker error is different this time:

Undefined symbols for architecture x86_64:
  "Swift.Dictionary.subscript.materializeForSet : (A) -> B?", referenced from:
      protocol witness for _Test.MyProtocol.subscript.materializeForSet : (A.KeyType) -> A.ValueType? in conformance <A, B where A: Swift.Hashable> [A : B] : _Test.MyProtocol in _Test in TestFile.o
0

There are 0 answers