# Key​Value​Pairs

Cosmologies seek to create order by dividing existence into discrete, interdependent parts. Thinkers in every society throughout history have posited various arrangements — though Natural numbers being what they are, there are only so many ways to slice the ontological pie.

There are dichotomies like 陰陽 ( yīnyáng ) ( ) : incontrovertible and self-evident (albeit reductive). There are trinities, which position man in relation to heaven and earth. One might divide everything into four, like the ancient Greeks with the elements of earth, water, air, and fire. Or you could carve things into five, like the Chinese with Wood ( ) , Fire ( huǒ ) , Earth ( ) , Metal ( jīn ) , and Water ( shuǐ ) . Still not satisfied? Perhaps the eight-part 八卦 (bāguà) will provide the answers that you seek:

 Trigram ☰ ☱ ☲ ☳ ☴ ☵ ☶ ☷ Nature 天 ( Heaven ) 澤 ( Lake / Marsh ) 火 ( Fire ) 雷 ( Thunder ) 風 ( Wind ) 水 ( Water ) 山 ( Mountain ) 地 ( Ground )

Despite whatever galaxy brain opinion we may have about computer science, the pragmatic philosophy of day-to-day programming more closely aligns with a mundane cosmology; less imago universi, more じゃんけん jan-ken ( Rock-Paper-Scissors ✊🤚✌️ ) .

For a moment, ponder the mystical truths of fundamental Swift collection types:

Arrays are ordered collections of values.
Sets are unordered collections of unique values.
Dictionaries are unordered collections of key-value associations. The Book of Swift

Thus compared to the pantheon of `java.util` collections or `std` containers, Swift offers a coherent coalition of three. Yet, just as we no longer explain everyday phenomena strictly in terms of humors or æther, we must reject this formulation. Such a model is incomplete.

We could stretch our understanding of sets to incorporate `OptionSet` (as explained in a previous article), but we’d be remiss to try and shoehorn `Range` and `ClosedRange` into the same bucket as `Array` — and that’s to say nothing of the panoply of Swift Collection Protocols (an article in dire need of revision).

This week on NSHipster, we’ll take a look at `KeyValuePairs`, a small collection type that challenges our fundamental distinctions between `Array`, `Set`, and `Dictionary`. In the process, we’ll gain a new appreciation and a deeper understanding of the way things work in Swift.

`KeyValuePairs` is a structure in the Swift standard library that — surprise, surprise — represents a collection of key-value pairs.

``````struct KeyValuePairs<Key, Value>: ExpressibleByDictionaryLiteral,
RandomAccessCollection
{
typealias Element = (key: Key, value: Value)
typealias Index = Int
typealias Indices = Range<Int>
typealias SubSequence = Slice<KeyValuePairs>

…
}
``````

This truncated declaration highlights the defining features of `KeyValuePairs`:

• Its ability to be expressed by a dictionary literal
• Its capabilities as a random-access collection

### Dictionary Literals

Literals allow us to represent values directly in source code, and Swift is rather unique among other languages by extending this functionality to our own custom types through protocols.

A dictionary literal represents a value as mapping of keys and values like so:

``````["key": "value"]
``````

However, the term “dictionary literal” is a slight misnomer, since a sequence of key-value pairs — not a `Dictionary` — are passed to the `ExpressibleByDictionaryLiteral` protocol’s required initializer:

``````protocol ExpressibleByDictionaryLiteral {
associatedtype Key
associatedtype Value

init(dictionaryLiteral elements: (Key, Value)...)
}
``````

This confusion was amplified by the existence of a `DictionaryLiteral` type, which was only recently renamed to `KeyValuePairs` in Swift 5. The name change served to both clarify its true nature and bolster use as a public API (and not some internal language construct).

You can create a `KeyValuesPairs` object with a dictionary literal (in fact, this is the only way to create one):

``````let pairs: KeyValuePairs<String, String> = [
"木": "wood",
"火": "fire",
"土": "ground",
"金": "metal",
"水": "water"
]
``````

### Random-Access Collections

`KeyValuePairs` conforms to `RandomAccessCollection`, which allows its contents to be retrieved by (in this case, `Int`) indices. In contrast to `Array`, `KeyValuePairs` doesn’t conform to `RangeReplaceableCollection`, so you can’t append elements or remove individual elements at indices or ranges. This narrowly constrains `KeyValuePairs`, such that it’s effectively immutable once initialized from a dictionary literal.

These functional limitations are the key to understanding its narrow application in the standard library.

## KeyValuePairs in the Wild

Across the Swift standard library and Apple SDK, `KeyValuePairs` are found in just two places:

``````struct Mirror {
init<Subject>(_ subject: Subject,
children: KeyValuePairs<String, Any>,
displayStyle: DisplayStyle? = nil,
ancestorRepresentation: AncestorRepresentation = .generated)
}

typealias RGBA = UInt32
typealias RGBAComponents = (UInt8, UInt8, UInt8, UInt8)

let color: RGBA = 0xFFEFD5FF
let mirror = Mirror(color,
children: ["name": "Papaya Whip",
"components": (0xFF, 0xEF, 0xD5, 0xFF) as RGBAComponents],
displayStyle: .struct)

mirror.children.first(where: { (label, _) in label == "name" })?.value
// "Papaya Whip"
``````
``````@dynamicCallable
struct KeywordCallable {
func dynamicallyCall(withKeywordArguments args: KeyValuePairs<String, Int>) -> Int {
return args.count
}
}

let object = KeywordCallable()
object(a: 1, 2) // desugars to `object.dynamicallyCall(withKeywordArguments: ["a": 1, "": 2])`
``````

On both occasions, `KeyValuePairs` is employed as an alternative to `[(Key, Value)]` to enforce restraint by the caller. Without any other public initializers, `KeyValuePairs` can only be constructed from dictionary literals, and can’t be constructed dynamically.

## Working with KeyValuePairs Values

If you want to do any kind of work with a `KeyValuePairs`, you’ll first want to convert it into a conventional `Collection` type — either `Array` or `Dictionary`.

### Converting to Arrays

`KeyValuePairs` is a `Sequence`, by virtue of its conformance to `RandomAccessCollection` (and therefore `Collection`). When we pass it to the corresponding `Array` initializer, it becomes an array of its associated `Element` type (`(Key, Value)`).

``````let arrayOfPairs: [(Key, Value)] = Array(pairs)
``````

Though, if you just want to iterate over each key-value pair, it’s conformance to `Sequence` means that you can pass it directly to a `for-in` loop:

``````for (key, value) in pairs {
…
}
``````

You can always create an `Array` from a `KeyValuePairs` object, but creating `Dictionary` is more complicated.

## Converting to Dictionaries

There are four built-in types that conform to `ExpressibleByDictionaryLiteral`:

• `Dictionary`
• `NSDictionary`
• `NSMutableDictionary`
• `KeyValuePairs`

Each of the three dictionary types constitutes a surjective mapping, such that every value element has one or more corresponding keys. `KeyValuePairs` is the odd one out: it instead maintains an ordered list of tuples that allows for duplicate key associations.

`Dictionary` got a number of convenient initializers in Swift 4 thanks to SE-0165 (thanks, Nate!), including `init(uniqueKeysWithValues:)`, `init(_:uniquingKeysWith:)`, and `init(grouping:by)`

Consider the following example that constructs a `KeyValuePairs` object with a duplicate key:

``````let pairsWithDuplicateKey: KeyValuePairs<String, String> = [
"天": "Heaven",
"澤": "Lake",
"澤": "Marsh",
…
]
``````

Attempting to pass this to `init(uniqueKeysWithValues:)` results in a fatal error:

``````Dictionary<String, Int>(uniqueKeysWithValues: Array(pairsWithDuplicateKey))
// Fatal error: Duplicate values for key: '澤'
``````

Instead, you must either specify which value to map or map

``````Dictionary(Array(pairsWithDuplicateKey),
uniquingKeysWith: { (first, _) in first })
// ["澤": "Lake", …]

Dictionary(Array(pairsWithDuplicateKey),
uniquingKeysWith: { (_, last) in last })
// ["澤": "Marsh", …]

Dictionary(grouping: Array(pairsWithDuplicateKey),
by: { (pair) in pair.value })
// ["澤": ["Lake", "Marsh"], …]
``````

Outside of its narrow application in the standard library, `KeyValuePairs` are unlikely to make an appearance in your own codebase. You’re almost always better off going with a simple `[(Key, Value)]` tuple array.

Much as today’s Standard Model more closely resembles the cacophony of a zoo than the musica universalis of celestial spheres, `KeyValuePairs` challenges our tripartite view of Swift collection types. But like all cosmological exceptions — though uncomfortable or even unwelcome at times — it serves to expand our understanding.

That’s indeed its key value.

NSMutableHipster

Questions? Corrections? Issues and pull requests are always welcome.

This article uses Swift version 5.1. Find status information for all articles on the status page.

Written by
Mattt

Mattt (@mattt) is a writer and developer in Portland, Oregon. He is the founder of NSHipster and Flight School, and the creator of several open source libraries, including AFNetworking and Alamofire.

Next Article

# bless

The process of booting a computer is a small miracle. Starting with a blank slate, a computer incrementally runs smaller, simpler programs to load larger, more capable programs into memory, until it finally has everything it needs to run the operating system itself.