←back to thread

Go subtleties

(harrisoncramer.me)
235 points darccio | 1 comments | | HN request time: 0s | source
Show context
valzam ◴[] No.45666643[source]
Great list of why one can love and hate Go. I really did enjoy writing it but you never get the sense that you can be truly certain your code is robust because of subtle behaviour around nil.
replies(3): >>45666654 #>>45667227 #>>45671606 #
valzam ◴[] No.45666654[source]
I guess as a corollary, Go really rewards writing the dumbest code possible. No advanced type shenanigans, no overuse of interfaces, no complex composition of types. Then you will end up with a very fast, resource light system that just runs forever.
replies(5): >>45666706 #>>45666893 #>>45669853 #>>45671891 #>>45672663 #
h4ck_th3_pl4n3t ◴[] No.45671891[source]
Oh boi, all my RW mutexes for maps across goroutines would disagree.
replies(1): >>45672481 #
gethly ◴[] No.45672481[source]
Use sync.Map or create simple wrapper to control access.
replies(1): >>45674040 #
mook ◴[] No.45674040[source]
… the documentation for sync.Map literally says:

> The Map type is specialized. Most code should use a plain Go map instead, with separate locking or coordination, for better type safety and to make it easier to maintain other invariants along with the map content.

The documentation basically says that it's optimized for some cases that wouldn't affect the complaint above.

replies(2): >>45674709 #>>45676715 #
1. h4ck_th3_pl4n3t ◴[] No.45676715[source]
Well, sync.Map is based on atomics which comes with limitations on its own as you have to use specific (potentially conflicting) hash keys for it.

What I wanted to point towards with my earlier comment is that sync.Map doesn't use resource based mutexes, it uses one mutex for everything which will always be the slowest case.

There's no real borrowing concept in Go, as there would be in Rust for that case, and if you argue that simplicity should be preferred then normal map[] should be threadsafe by default, which, in return, likely will require compile time expansion because of generics.

The core value of Go's "we want simplicity" approach always feels like it's a facade, because there is so many exceptions and footguns along the way. These footguns almost always were conscious decisions where they could have made a decision to break legacy behavior for better simplicity but decided that this is not what they want, which is weird as it's not fitting the initial language design promise.