Causes of disordered dictionary in Swift

Everyone knows that dictionaries in swift are unordered collections, there is no problem with that. I've noticed some behavior that I can't explain and hope someone can help me. The first variant We have a very simple code:

struct Test { let dict = [1: “1”, 2: “2”, 3: “3”, 4: “4”, 5: “5”]

func test() {
    for i in dict {
        print(i)
    }
}

} If you call test() several times in a row, the output to the console on my computer looks something like this:

(key: 5, value: “5”) (key: 1, value: “1”) (key: 2, value: “2”) (key: 3, value: “3”) (key: 4, value: “4”)


(key: 2, value: “2”) (key: 3, value: “3”) (key: 1, value: “1”) (key: 4, value: “4”) (key: 5, value: “5”)


(key: 1, value: “1”) (key: 3, value: “3”) (key: 2, value: “2”) (key: 5, value: “5”) (key: 4, value: “4”)

At each new for loop we get a random order of elements It seemed logical to me, because a dictionary is an unordered collection and this is correct behavior. However The second variant the same code on my colleague's computer, but in the console we see something like this: (key: 2, value: “2”) (key: 3, value: “3”) (key: 1, value: “1”) (key: 4, value: “4”) (key: 5, value: “5”)


(key: 2, value: “2”) (key: 3, value: “3”) (key: 1, value: “1”) (key: 4, value: “4”) (key: 5, value: “5”)


(key: 2, value: “2”) (key: 3, value: “3”) (key: 1, value: “1”) (key: 4, value: “4”) (key: 5, value: “5”)

always, within the same session, we get the same order in print(i)

We didn't use Playground, within which there may be differences, but a real project. swift version 5+ we tested on Xcode 14+, 15+ (at first I thought it was because the first version had 14 and the second version had 15, but then a third colleague with Xcode 15 had the behavior from the first scenario)

we did a lot of checks, several dozens of times and always got that on one computer random output of items to the console, and in another case disordered only in the first output to the console

Thanks

At each new for loop we get a random order of element

That surprises me. Please post more code. In particular, are you calling test() on the same object each time, or are you creating a new Test object?

The source for the swift dictionary is here:

https://github.com/swiftlang/swift/blob/main/stdlib/public/core/Dictionary.swift

It start with a lot of comments which you might like to read. In particular, at line 331:

The order of key-value pairs in a dictionary is stable between mutations but is otherwise unpredictable.

There are data structures that can change order between uses - for example, splay trees reorganise themselves so that recently- or frequently-used elements will be found more quickly. I don’t believe that the Swift dictionary is such a data strucutre.

on my colleague's computer [...] within the same session, we get the same order in print(i)

Are these different computers running different versions of macOS (if testing a Mac app) or iOS device / simulator (if testing a target device)?

There was a cutover point in the OS where this behavior changed. Before they rewrote Dictionary in Swift, the old Objective-C implementation produced stable orderings for the same set of keys across all dictionaries in a given process. But after, the orderings are unstable between individual dictionary instances.

See this thread for some more discussion of this effect.

But after, the orderings are unstable between individual dictionary instances

They’re still supposed to be stable if you iterate the same object a second time, right?

That’s correct, for the same object. The original description didn’t clarify if you were doing this, with a single dictionary:

let object = Test()
object.test()
object.test()

...or doing this, with a new dictionary each time:

Test().test()
Test().test()

If would be unexpected to get the varying results if doing the first case.

Causes of disordered dictionary in Swift
 
 
Q