> Java can't do this because the primitive types are not objects.
So this excuses the awful Java genetic how? "It smells like sewage in the basement because the basement is full of sewage." In addition, generics over primitive/stack/value types (including mathematical operators) is working just fine in the latest iteration of C#.
It doesn't. Picking an area where Java is weak and where Go happens to be decent is the very definition of cherry picking. Go happens to do poorly in almost every other area and Java does meh in many (erasure, unsoundness, etc.) and excellent in others (profile-guided devirtualization).
really? Is Go that bad? Write a server that does communication or emulate select in Go in other languages. Go is really effective at writing things fast at the same time that it has value types and can scale not only in I/O but also in multi-core in a way that is easier than anything I saw before. I am a mainly C++ person but I must admit that the cost/investment ratio in Go is really good for writing server-side stuff.
> Write a server that does communication or emulate select in Go in other languages.
I just did that - I've been working on a very similar thing to goduplicator (a mirroring proxy), however with an additional requirement that it must not add latency to the primary communication path, e.g must connect mirrors asynchronously and buffer data instead of waiting for a slow mirror.
I chose Rust and the resulting code has been at the same time simpler, faster and uses 3x fewer memory than the Go implementation. I have not only select!, but also things like join! or try_join! at my disposal, way simpler to use than channels and waitgroups.
Also looks like closing connections in Go is a mess. In Rust I just remove a connection value from the vector and I'm done. In Go they have to close them manually, but defer is quite useless in async code, where the connections are passed to a coroutine.
In Rust I can also interleave work concurrently on a single thread with async, avoiding synchronisation. In Go I'd have to spawn goroutines and then coordinate them through channels which would be both more complex, more costly to execute and more risky.
So IMHO Go is definitely an interesting language to write concurrent networking code in, but feels quite incomplete to me. You get products but no sum types, you get select (which is kinda sum for channels) but not join (which is an analogy of a product for channels). You get semi-automatic cleanup with defer, but it is tied to a lexical scope ignoring the fact that goroutines can outlive it.
Well, for latency you do have to deal with the GC very carefully, but the investment/ratio in Go is very good. It is just not for absolutely every use case, like everything else in your toolbox.
Investment ratio in Go is only good because of how little you have to invest. In Rust the required investment is bigger, but you get a lot more in return. Not sure about which ratio is really better.
GC is only a minor reason I chose Rust over Go for a networking related project. Despite having a GC, Go definitely feels more low-level and less structured than Rust, and leads to code that is longer and harder to reason about.
It is very similar to how a language with only a goto instruction to do control flow would be definitely simpler/smaller than a language that supports functions, loops and conditions, but the actual programs written in it would be brittle and harder to understand.
I'm personally no fan of Go (mostly due to the ergonomics of the standard library), but all this about generics is throwing the baby out with the bathwater. Go has a fantastic generics design.
> cost/investment ratio in Go is really good for writing server-side stuff.
I’m a big fan of Go, and I’ve never been bullish on generics, but I really don’t see what is good about this design. I’m really not interested in generics with a runtime penalty even if it makes binaries smaller. I also think the constraint system needs work, and there needs to be a mechanism for generic methods. It’s possible for Go to get all of these things, but the current form leaves a lot to be desired. Rust’s trait system is best in class as far as I can tell, and I’ve criticized Rust often in the past.
The context is what was said above: Java generics can't abstract over primitive types, they only work for objects. That is awful, and it is important, because this one limitation is the only thing that makes the implementation of generics in Java possible and simple.
If generics had had to actually support ArrayList<int>, they would have required significant changes to how ArrayList is stored in memory, and to how a lot functions which work with generic types are actually compiled. Instead, Java has the easy path in the implementation: since everything only works with reference types, there's no need for multiple copies of a function to work with different types.
Of course, this means that sum<Integer>(new Integer[1000000]) is going to be orders of magnitude slower than sumInts(new int[1000000]).
It is unfortunate, but that was the only way Generics could ship at the time in a backwards compatible way. But I don’t think it is fair to call it awful, especially knowing the context. Also, when it does show up as a performance bottleneck, it is trivial to fix.
So this excuses the awful Java genetic how? "It smells like sewage in the basement because the basement is full of sewage." In addition, generics over primitive/stack/value types (including mathematical operators) is working just fine in the latest iteration of C#.