9 ms·
> While I understand the reason for this (i.e.: to avoid developers relying in a specific iteration order), I still find it weird, and I think this is something
by cempaka 2y ago
> While I understand the reason for this (i.e.: to avoid developers relying in a specific iteration order), I still find it weird, and I think this is something unique for Go.
Haha well, fun fact, Java did this as well after a bunch of code was broken by a JDK upgrade which changed HashMap iteration order that programmers had been relying upon. Java does at least have ordered maps in the standard lib though. IMO it is a questionable decision to spend CPU resources on randomization in order to mollycoddle programmers with a flawed understanding of an API like this, but then again I'm not the one who gets the backlash when their stuff breaks.
Also, on the subject of nullability, while JSR305 may be considered dead, there's still pretty active work on the Java nullability question both from the angle of tooling (https://www.infoq.com/news/2024/08/jspecify-java-nullability/ https://www.infoq.com/news/2024/08/jspecify-java-nullability...) and language design (https://openjdk.org/jeps/8316779 https://openjdk.org/jeps/8316779).
- jillesvangurp 2y agoIt's one of the things I like in Kotlin: it defaults to using ordered maps. It also has default arguments in functions, lambda functions, and of course nullable types.
- kevindamm 2y agoI was about to comment the same. Also happened in absl (Google's alternative to the STL template library for C++ which started its life as GTL) -- when changing the default hash function for unordered maps it led to breaking changes in both test and production code that had depended on it. OrderedDict types are nice sometimes but shouldn't be the default behavior, IMO. There are good reasons for the second point (about default/named parameters) -- any calling code is making some assumptions based on that default value so there's a risk it can't be changed or added to. If you really want a default value, make a wrapper function for it. In the example it would be a simple matter of defining ReplaceAll with three arguments that always passes -1 to Replace(...)
- Groxx 2y agoBecause it came up recently for me (triggered a starvation bug), a caution for people expecting Go to randomize everything like this: Blocked channel reads and writes are unblocked in FIFO order, not random. Mutexes are similar (afaict not quite identical, but the intent is the same). Go randomizes a lot and I am thrilled they do that, and I knew about mutexes already, but the chan part was a surprise to me. It's reasonable and matches mutexes, so that's probably for the better, but still a bit oof.
- hombre_fatal 2y agoMeh, what if people rely on randomness. They should flip between random and ordered at random too.
- therein 2y agoYeah, gotta keep the programmer on his toes. He needs to embrace non-determinism, and second guess everything. In case Go developer switches to a different language, we don't want to build bad habits. Map key iteration should be non-deterministically deterministic.
- ithkuil 2y agoWell, every once in a while the random order will look like it's ordered
- akira2501 2y ago> Meh, what if people rely on randomness. Then they are creating fragile software. They're always one language version upgrade away from disaster.
- deleted 2y ago[deleted]
- hombre_fatal 2y agoYes, but that criticism already applies to the original iteration order before Go introduces a performance penalty by intentionally randomizing order on every iteration just so people can't rely on it.
- jsnell 2y agoPerl has done per-run randomization of the iteration order as well for a while (more than a decade). % repeat 5 perl -e '%h=(a => 1, b => 2, c=> 3); print for keys %h; print "\n"' bca cba bac bac bac
- h4ck_th3_pl4n3t 2y ago[flagged]
- vessenes 2y agoCounterpoint - Perl 5 should be (and frankly probably is) required reading for all language designers. You may not like its opinionated point of view, but it glued together the early internet, and occupied a niche so large for so long that calling it a niche is underselling it. Misunderstanding why Perl worked, and what worked about it is a miss in an any serious software engineer’s education.
- Dylan16807 2y agoNotice how almost all of those are just a variable name or a number on a line by itself. Those being valid programs says very little about Perl as a language. A few semicolons being okay in a mix with the above doesn't say much either, and the couple gnarliest examples happened to hit #, the comment character, so the rest isn't even being treated as code.
- okwhateverdude 2y agoCute story on why that came to be. At Booking.com, a degenerate case that lead to a DoS that you could cause with specially crafted URLs (I think, memory is a bit foggy) spurned Yves Orton to do that hacking. And it broke a lot of code where the ordering had been consistent enough that people relied on it.
- darrenf 2y agoWay longer than a decade. You can see it in the perlfunc man page way back in 1996[0]. Of the same vintage is `Tie::IxHash`, which retains insertion order % repeat 5 perl -MTie::IxHash -E 'tie my %foo, "Tie::IxHash"; @foo{qw{ c a b }} = (1)x3; printf("%s%s%s\n",keys %foo)' cab cab cab cab cab [0] https://metacpan.org/release/NI-S/perl5.003_02a/view/pod/perlfunc.pod#keys-ASSOC_ARRAY https://metacpan.org/release/NI-S/perl5.003_02a/view/pod/per...
- IshKebab 2y agoI wouldn't call it mollycoddling. I can understand why people make that mistake. Interfaces should be designed to reduce the chance of mistakes as much as possible, under the knowledge that people (including you!) make mistakes. They shouldn't be designed under the assumption that people always read and understand the manual and never make mistakes. That's why we don't do `load` and `load_safe`; we do `load` and `load_unsafe`.
- kbolino 2y agoThey just added custom iterators ("range over func") to the language in 1.23 but somehow missed the obvious opportunity to add e.g. maps.SortedByKeys. It's clunky to write: for _, k := range slices.Sorted(maps.Keys(m)) { v := m[k] _ = v // do something with k and v } though, it's not as bad as before: keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } slices.Sort(keys) for _, k := range keys { v := m[k] _ = v }
- 38 2y ago> maps.SortedByKeys thats what you call overfitting kids
- kbolino 2y agoWhatever you think the best name for it is, it's still missing from the library.
- 38 2y agothe point is you dont need it. by your own admission, it would save literally 0 lines of code from your current example. you need discipline when adding sugar otherwise you can ruin a language.
- kbolino 2y agoI said no such thing. First, it would save one line of code (v := m[k]). Second, it would also allow an optimization. When iterating a map directly, you have both the key and the value at the same time. However, since we iterate only the keys here, we then have to look up the value anew for each key. That takes extra time and, for large maps, will thrash the CPU cache. So the following would be both fewer lines of code and faster: for k, v := range maps.Sorted(m) { // do something with k and v } Making common operations clear and concise is not mere sugar in my opinion. It not only improves the developer experience, it also clarifies the developer's intent, which enables better optimizations, and allows bugs and traps to be addressed in one place, instead of languishing in far-flung places.
- barsonme 2y ago> IMO it is a questionable decision to spend CPU resources on randomization … It takes about 3 ns to choose a random starting bucket, which is basically free relative to the iteration itself.
- worik 2y ago> Java does at least have ordered maps Weird An "ordered map" is not a hash table. I think they want a tree. But you can get the keys and sort them. I really do not see the problem Use a tree if order matters, Hash if not. (Since I am not a Go programmer, maybe I missed something)
- layer8 2y agoJava’s LinkedHashMap is a hash table with an additional linked-list structure on the entries that records the insertion order. The map is thus ordered by insertion order, an order that is independent from the keys. A map ordered by keys is a SortedMap in Java. While ordered, LinkedHashMap is not a SortedMap. In other words, unordered < ordered < sorted.
- masklinn 2y ago> An "ordered map" is not a hash table. I think they want a tree. An ordered map is absolutely a hashmap. > But you can get the keys and sort them. That gives you a sorted thing, which is completely different. > Use a tree if order matters, Hash if not. That is incorrect. “Ordered” in the context of maps generally denotes the preservation of insertion order, and more rarely the ability to change that order. Trees don’t help with that, quite the opposite.
- worik 2y ago> An ordered map is absolutely a hashmap I have never heard of O(1) insert and retrieval from anything ordered. So, no. An ordered map is not a hashmap
- masklinn 2y ago> I have never heard of O(1) insert and retrieval from anything ordered. Then you’ve not gotten out much. Here’s one: https://docs.python.org/3/library/stdtypes.html#dict https://docs.python.org/3/library/stdtypes.html#dict Here’s an other one: https://docs.python.org/3/library/collections.html#collections.OrderedDict https://docs.python.org/3/library/collections.html#collectio... Here’s a third one: https://docs.rs/indexmap/latest/indexmap/map/struct.IndexMap.html https://docs.rs/indexmap/latest/indexmap/map/struct.IndexMap... And a fourth: https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/util/LinkedHashMap.html https://docs.oracle.com/en/java/javase/22/docs/api/java.base... > So, no. An ordered map is not a hashmap Still wrong.
- layer8 2y ago> Java did this as well after a bunch of code was broken by a JDK upgrade which changed HashMap iteration order that programmers had been relying upon. This is incorrect (or I’m misunderstanding you). OpenJDK’s HashMap doesn’t use randomization, and the iteration order is thus deterministic under that implementation, although the API specification does not guarantee it. To mitigate DoS attacks, keys in the same hash bucket are stored as a balanced tree. For keys that implement Comparable (strings in particular), this guarantees O(n log n).
- cempaka 2y agoAh you're right, what I had in mind was the iteration order of the immutable/unmodifiable maps created by Collections.unmodifiableMap() or Map.of(): https://docs.oracle.com/en/java/javase/20/core/creating-immutable-lists-sets-and-maps.html https://docs.oracle.com/en/java/javase/20/core/creating-immu...