[1] https://github.com/polynya-dev/pg2iceberg
[2] https://www.polarsignals.com/blog/posts/2024/05/28/mostly-ds...
It seems like you lose a lot (automatic memory safety, simple language, easy concurrency) and gain very little.
A lot of libs/packages in Go's stdlib also has this problem. They like to package everything in a very tight interface (very obvious example includes crypto/* and http), without exposing implementation detail to the end user.
Doing this of course has it's benefits, but if the feature provided by the stdlib slightly don't fit you needs, then you might have to write your own (potentially unsafe and/or less performant) one from zero.
Rust is great overall, but there's some oddities. For example their lib.rs / `mod` is very, very unintuitive, it felt overdesigned and unnecessarily complex (just see [their book]). I like what Go or Java did to their lib/package systems, it's much better that way.
[their book]: https://doc.rust-lang.org/stable/book/ch07-05-separating-mod...
As you note it's just pain with no gain to properly hide them. Users can't readily work around bugs or extend functionality.
The biggest gripe I have with Go is the lack of *any* compile time check for mutex. Even C++ has extensions like ABSL_GUARDED_BY. For a language so proud on concurrency, it is strange not to have any guardrails.
If you have a mutex on a structure, linters such as are packaged into Goland will catch oversights quite effectively.
If you are using fancier concurrency structures, you should consider channels instead.
But generally I would agree that if you need to code parallel execution, channels are a good way to do it, because you can avoid race conditions if you share data only over channels. The biggest problem is that a lot of people don't understand, that channels with a buffer larger than 1 are a sign of problems in the architecture.
There is a type of parallel programming with workers for specific functions, that always leads to performance issues. The problem is you need to right-guess the distribution of work, when you have to define the amount of workers for a specific function. At least one go routine for one request is a much better approach than function-specific workers.
So, in production?
For example, I can transmit the response to the client and then free the memory afterwards so they're not kept waiting.