[swift-evolution] [Proposal Draft] Provide Custom Collections for Dictionary Keys and Values

Nate Cook natecook at gmail.com
Wed Oct 12 10:31:39 CDT 2016


Thanks for your feedback! Response below.

> On Oct 12, 2016, at 5:40 AM, Daniel Vollmer via swift-evolution <swift-evolution at swift.org> wrote:
> 
> Hi,
> 
> I very much think the points mentioned in the motivation are worth addressing (and IMO this is not an area where “maybe the optimizer can be made smarter” can cut it; I want performance guarantees, not hopes).
> 
>> On 11 Oct 2016, at 23:28, Nate Cook via swift-evolution <swift-evolution at swift.org> wrote:
> 
> [snip]
> 
> On a shallow read I like presented approach, except for
> 
>> Both the keys and values collections share the same index type as Dictionary. This allows the above sample to be rewritten as:
>> 
>> // Using `dict.keys.index(of:)`
>> if let i = dict.keys.index(of: "one") {
>>    dict.values[i].append(1)
>> } else {
>>    dict["one"] = [1]
>> }
> 
> The asymmetry between the if / else branches seems ugly to me. That is once obtaining the value “directly” from dict, and once through the values-view. I don’t have a great solution here, but is is possible to subscript the dict by its `Index` as well as its `Key`?
> 
> ```
> // Using `dict.keys.index(of:)`
> if let i = dict.keys.index(of: "one") {
>    dict[i].append(1)
> } else {
>    dict["one"] = [1]
> }
> ```

I share your concern with this, and there is an approach that would make this kind of interface possible. Basically, what you're describing here would necessitate changing Dictionary to act like a mutable collection of values, and instead of presenting `keys` and `values` views, we would probably offer `keys` and `keysAndValues` (or something) views. With that new model, we'd have code like the following:

var dict = ["one": [1], "two": [2, 2], "three": [3, 3, 3]]

// Iterating the dictionary itself would be like we now iterate the values collection
for val in dict {
	print(val)
}
// Output is just the values (unordered as usual)
// [1]
// [3, 3, 3]
// [2, 2]

// Iterating a new view would act like the dictionary currently does
for (key, val) in dict.keysAndValues {
	print(key, val)
}
// "one", [1]
// "three", [3, 3, 3]
// "two", [2, 2]

Any sequence or collections operations on the dictionary itself would only interact with values:

print(dict.first)
// Optional([1])
print(dict.first(where: { $0.count > 2 }))
// Optional([3, 3, 3])

I'm not strictly opposed to this approach, but I do prefer the way the current dictionary implementation presents its elements as key-value pairs. When you iterate a dictionary you're seeing all of its contents, which I like, but there are clear tradeoffs between the two. Making Dictionary a collection of values is also a much more significant change than the one proposed—we'd need to do some research into the ways dictionaries are used to know how much larger an effect that would be.

What do others think of this as an alternative solution for the motivating issues? Does anyone actually use indices right now to work with dictionaries, or is key-based read/write pretty much the only interface?

> On another note, I’m not sure whether there is a way (or whether it’s even worth trying) to avoid hashing the key twice when the `else` branch is taken.

This is outside the scope of the proposal, but as far as I can see I don't think there's a solution for this that wouldn't overly expose the internal workings of the dictionary.

Thanks again,
Nate


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161012/fe58cf07/attachment.html>


More information about the swift-evolution mailing list