| Go is woefully missing some really key features, which you encounter when tuning it for high performance. My list of grievances: - Dep handling was never considered. Makes sense given Google's monorepo but thats not how the world works. - Stdlib just loosely wraps posix features with many C flags copied verbatim. These APIs are old and could use a refresh but Go never bothered. - No easy way to construct arenas/pools. Once you go down this route you have a great headache of releasing in the right places. The GC doesn't cut it, you need pools sometimes - Debugging basically doesn't work on some OSes. No easy way to attach gdb and see what's happening. Doubly so if you use Cgo - Similarly, Go doesnt bother to hide the differences of different OSes. Up to you as the programmer. Again not surprising for Google's all Linux world. If everything is Linux then OS difference doesnt matter. But even Python does a better job here. - Logging is poorly thought out as evidenced by multitude of third-party log packages. Anemic compiler means you can't get verbose logging without paying a performance penalty. - No RAII. Defers are a lazy attempt at this, but they're not even close to being as good as RAII. This is probably the biggest point where you realize Go can't dethrone C++ - Tricky Close() semantics force you to architect entire program around who will close() things at end of their lifetime. Lots of terrible hacks ensue when people build something that works but realize close ownership is ambiguous and rightfully don't want to rebuild it all - Channels don't have a good way to deal with errors. You're forced to come up with an ad hoc solution to deal with your graph of goroutines/channels when one node errors - No supervision tree. Erlang existed far before Go but they didn't learn from this key feature. But it would greatly enhance Go to have it - Hacky reflection semantics that cause subtle runtime bugs when a JSON struct field's name starts with a lowercase letter. And of course, there are no generics, the larger issue here. I was hopeful that Go would fix some of these things before it went 1.0 and locked in its syntax. Sadly that didn't happen as it was likely already locked in at Google. Go is ultimately kind of brain dead, useful for some very particular features but not so compelling that it can replace any other language. |
I disagree with these. Go runtime/stdlib is architected to work around many many POSIX headaches and design bugs, hiding them completely from programmers, and to be fully portable. For instance:
* Concurrency is completely redesigned (goroutines). * Signal handling is redesigned and doesn't cause bugs when interacting with concurrency. * Forking/Exec'ing is redesigned not to cause fd leaks in subprocesses (all file descriptors are marked as O_CLOEXEC, in a race-free way), nor have races while interacting with concurrency * Sockets are exposed through a higher-level API (Dialer/Listener). * epoll is not exposed but transparently used by a single thread to handle all supported file descriptors without wasting OS threads, to improve performance
In fact, I think the only thing that is pretty much low-level is os.File and filesystem access in general, which tends to expose lower-level details.