Currently I'm working on a data structure intended to store store key-value pairs uniquely and keep them sorted by key. Essentially it is a sorted dictionary and as such I am seeking to keep as much of the Collection and Dictionary semantics of Swift as I can.
In the documentation and Swift source (as best as I can find), Dictionaries have two subscripts. One is the most commonly used subscript by key (Github source):
extension Dictionary {
...
public subscript(key: Key) -> Value? {
@inline(__always)
get {
return _variantBuffer.maybeGet(key)
}
set(newValue) {
if let x = newValue {
// FIXME(performance): this loads and discards the old value.
_variantBuffer.updateValue(x, forKey: key)
}
else {
// FIXME(performance): this loads and discards the old value.
removeValue(forKey: key)
}
}
}
...
}
And the second is a subscript by position/index (Github) source) as part of its conformance to the Collection protocol:
extension Dictionary: Collection {
...
public subscript(position: Index) -> Element {
return _variantBuffer.assertingGet(position)
}
...
}
When using these with a Dictionary keyed by something other than an Int
, they behave exactly as expected because the subscripts are distinguished by different parameter types, ie: String
vs Int
.
let stringKeys = ["One": 1, "Two": 2, "Three": 3]
stringKeys["One"] // 1
stringKeys[1] // ("Two", 2)
When Int
s are used as keys, the key subscript is used as desired.
let intKeys = [1: "One, 2: "Two, 3: "Three"]
intKeys[1] // "One"
How does the Dictionary type accomplish this? It would seem to me that the Index
and Key
parameters of the subscripts are both Int
and that the compiler should not know which was intended. Indeed, when I implement the same subscripts for my custom dictionary, the compiler gives exactly that error—"Ambiguous use of 'subscript'"—when I test it with Int
keys.
At first I wondered if one was a default provided in a protocol extension and overridden by a more specific implementation, but from what I can tell above that is not the case. The only other theory I have is that Index
is of some other type than 'Int` such that it remains unambiguous but I can't find my way to anything that confirms this. Can anyone shed some light on this? Beyond my immediate needs, it's quite a clever bit of behavior in Swift that I'd like to understand.
Thank you to all for reading and for your help!