And there's also the proc macro story (almost every project must compile proc_macro2 quote and syn before the actual project compilation even starts).
Blaming it on LLVM like another comment does misses the point. Any back end is slow if you throw a truck-load of code at it.
I'm not saying monomorphization is intrinsically bad. (My current hobby language works this way.) But it's certainly a trade-off with real costs and the Go folks didn't want their users to have to pay those costs.
So I don't think you can say that this has nothing to do with the type system. Here is a restriction in the Go type system that was specifically introduced to allow a broad range of implementation choices. To avoid being forced to choose slow compilers or slow code: https://research.swtch.com/generic
The Go type system and the way it does generics is directly designed to allow fast compile times.
Yes, but that is now a different runtime cost which Go also didn't want to pay.
The language goes to great pains to give you pretty good control over layout in memory and avoid the "spray of tiny objects on the heap with pointers between them" that you get in Java and most other managed languages.
I think Swift maybe does something more clever with witness tables, but I don't recally exactly how it works.
It's not an easy problem.
Pestov actually wrote a long explanation of what it is that Swift does there[1,2]. And I’m almost sure you’ve already seen it, but it’s been on my reading list forever and I’m hoping that maybe if I can’t get myself to read it, than somebody else will see this comment, get interested and do it.
If you're not aiming for the highest possible performance, you can type erase your generics and avoid the monomorphization bloat. Rust couldn't because they wanted to compete with C++, but Go definitely could have.
However, OCaml has a very fast compiler, comparable in speed to Go. So a more expressive type system is not necessarily leading to long compilation times.
Furthermore, Scala and Haskell incremental type checking is faster than full compilation and fast enough for interactive use. I would love to see some evidence that Golang devs are actually more productive than Scala or Haskell devs. So many variables probably influence dev productivity and controlling for them while doing a sufficiently powered experiment is very expensive.
For an apples-to-apples comparison of compilation speed, you should either include the time it takes go generate to run, and the IDE to re-index all the crap it emits, or you should count the number of lines of code in the largest intermediate representation that C++ or Rust has.
But that would be unfair to the very design choice of omitting metaprogramming while exposing the go/ast library to users to foster code generation.
OCaml and Haskell don't suffer from similar pain points, because interpreters, and JIT like tooling is also available.
One can happily develop with one toolchain, and press the red button for an optimised compiled build, when it actually matters.
Also both Swift and Rust have made the mistake to make used of the compiler backend that everyone avoids when they care about build performance, LLVM.
But you breezily claiming they made the same blunder as Java omits the fact that they didn't make the same blunder as Rust and Swift and end up with nightmarish compile times because of their type system.
Almost every language feature has difficult trade-offs. They considered iteration time a priority one feature and designed the language as such. It's very easy for someone looking at a language on paper to undervalue that feature but when you sit down and talk to users or watch them work, you realize that a fast feedback loop makes them more productive than almost any brilliant type system feature you can imagine.