4 Comments
User's avatar
drumchaku's avatar

Interestingly enough, maps (dicts) in Python are insertion-ordered. While this is a side effect of the current implementation, this behavior was useful enough that it was made standard. Somehow that doesn't apply to sets, though.

I must be solving a different category of problems in Go, though, because somehow I haven't yet need this behavior. I have one Java application where this is necessary.

The Coding Gopher's avatar

Spot on about Python dicts! It actually started as a CPython implementation detail in 3.6 and then became an official language guarantee in 3.7 because so many people relied on it (JSON round-tripping, config parsing, etc.). Sets, though, are a different beast IMO; they’re pure hash tables optimized for O(1) membership testing / set operations, so insertion order was never part of the contract. If you need an ordered set in Python you’d usually go for something like collections.OrderedDict (with a dummy value) or a third-party like sortedcontainers. Go takes the opposite stance on purpose. Maps are explicitly unordered, and the runtime randomizes iteration order every time to stop people from accidentally depending on hash order (which has bitten many, many languages). Most Go code I’ve seen solves this with a sorted slice when order actually matters, or just map[K]struct{} + manual sorting. The fact you haven’t hit the need yet is super common IMO; it usually only surfaces in UI-preserving, logging, + config-heavy code.

That one Java app sounds familiar! Was it a LinkedHashMap/LinkedHashSet situation where you needed both insertion order + fast lookups?

Jonathan Ang's avatar

Thank you for this! My code was breaking during an assignment for a Distributed Systems class. it took me a couple of hours to realize that it is by design that Go iterates randomly. I truly held an implicit assumption about map ordering!

The Coding Gopher's avatar

My pleasure!

It happened to me recently with flaky unit tests in our pre-commit check runs as well