It still blows me away that people put their email address in forms, and that email marketing affects sales. I guess while they keep working, people will keep creating popups.
If you squint a little, you'll notice that go is pretty big on not hiding complexity. There are obvious exceptions to this such as the garbage collector, and heap/stack control.
I'm unsure if the intent of not including a map function was due to this, however with a for loop such as
for x := range ch {
slice = append(slice, x)
}
, it is immediately obvious there are allocations happening in the background.
The fact that map access, and slice access is not thread safe means there is no trickery going on in the background. The fact that it is not threadsafe means I don't need to worry about a lock if I only write to a map when it's created. Sure the compiler could take care of this - they have the race detector after all, but the compile speed is one of the design goals of go. I really like being able to compile in less than 1 second.
`sync.Map` however calls a function which implies there is more going on in the background.
If you follow the go mantra of share memory by communicate, don't communicate by sharing memory - handling data becomes a whole lot easier. It does allow you to share memory in case you do need the extra speed.
Like most things, all designs are a matter of trade offs. Sacrifice one thing for another. There are other languages that provide the functionality you desire - but I understand the frustration when one thing is 90% what you want.
Go obviously has room for improvement, and perhaps a native threadsafe map is one of those areas.
I'm not familiar with OMP, so please forgive me if I'm incorrect - but OMP from my quick search appears to be thread based, while go routines are much lighter weight than threads. They have their own scheduler - which like most things is both good and bad depending on what you want them for. If you use them as intended, the internal scheduler is a great design decision. This means I can happily spawn 10,000 without concern.
Additionally, combining them with the power of channels makes quick work of many tasks. Channels of course can be implemented in C++ too, but having the compiler take care of it for you with additional tools such as the race detector is very handy.
For a large set of problems, they are very nice to work with.
I had a 28/27" 4k monitor, but like the author I found it far too small (the pixel size) to use comfortably. Unfortunately I was working with legacy applications that didn't support scaling and couldn't adjust the DPI. I have no doubt it would be much nicer at 125/150%.
One thing that is certain is that people have different preferences. Certainly some people would enjoy the tiny pixels of the 27" 4k monitor at 100%.
My current setup is 2x24" 1920x1200 monitors. I have considered 3x24, 1x Ultra wide or 2x Ultra wide, but I'm not convinced I'd get the same comfort. I think that 3x 24, or 2x ultra wides would require to much head rotation to be comfortable.
I prefer the vertical break in the screen since it makes snapping windows easier. I'm starting to think that I might prefer a bit more real estate, as I often collapse the vertical file menu in my editor for a little extra room.