At that point aren't you just writing out the generics by hand? Why would you not want a built in language feature for that which saves you the trouble while simultaneously ensuring the code is correct.
What I’m arguing is that for most cases, the implementation and concretization are so easy to write by hand, are safe enough, and perform well enough, that I don’t think the downsides of having the compiler emit the concretizations are worth it. The downsides being the new complex language primitives that have lots of consequences that trickle out to the compiler, runtime, and ecosystem.
Unless I'm mistaken, the "generic type specifications" are just interfaces. Instead of specifying the concrete type of a function parameter, you specify which interface it needs to implement, and then everything else is the same (except you may need to define getters/setters if you need access to struct fields). There's no need to have a new language primitive. That's certainly how Rust does it anyway. And given that Go's interfaces are structurally typed, it'll be even simpler in Go.
I don't really understand the argument that generics are complex. As far as I can see, they're super simple.
In a weird way, with this technique, did Go have "manual generics" all along?
In the exact same way every langage without generics had generics all along: not in any meaningful way.
You could also use codegen hook to instantiate your pseudo-generics after all: https://www.reddit.com/r/rust/comments/5penft/comment/dcsgk7...
To-be-named-at-runtime is simply dynamic typing. It's polymorphism without static typing.
Generics based on type erasure, e.g. Java, wrap that with a type system hoping* to prove safety at compile time, yet compile to a single dynamicly typed implementation, that does not use this type info at runtime.
Generics based on code generation / specialization, e.g. C++, generate distinct run-time implementations with the type hard-coded. (Though you can plug in dynamic typing by making the hard-coded type a pointer.) In C++ this is more than optimization, it's semantics — you can specify distinct behavior for specific types.
JIT compilers can start from a single dynamic-dispatch implementation and generate specialized implemetations for some types, bridging the divide.
But in any case, the common meaning of "generics" is not merely polymorphism, it's polymorphism plus a type system where you _name_ the type you're gonna use.
I agree that lack of iterators is one area where there is permanent annoyance. Personally, I think that annoyance is a lot less than the other problems that come with generics (at least in other languages).
I'm not saying there aren't legitimate scenarios where generics simplify things. I'm completely convinced that there are. But holistically I don't think they outweigh all the other baggage that they come with.