The point isn't that it can't be useful.
In the real world, the amount of code I'm forced to understand that uses overly complicated abstractions is the issue. I'm glad one language finally took the opposite direction.
This may say more about the specific codebases you work in than it does the software world at large. I spend most of my time in a couple of languages that all have generics and don't experience the problem you describe.
Parametric polymorphic code is not hard to read at all - in fact, it is easier to reason about since it is universally quantified for all types.
go can iterate over arrays irregardless of the element type the same way with the same construct using "range", therefore "range" is polymorphic.
The real debate here is should the compiler be "privileged" or should there be API in userland to implement these behavior.
> Java, C#, Visual Basic .NET and Delphi have each introduced "generics" for parametric polymorphism.
Neither of those contradict my assertion that most programmers have never done work in a language where the type system can make guarantees that they can trust.
Outside of Java syntax noise, I really have my doubts that Java's parametric polymorphism is too complicated for the average programmer to understand.
public static <A> A identity(A a) { return a; }How many languages provide you a way to guarantee at the type level that the behavior of a function cannot be influenced by instantiation of type variables? I don't believe that to be true of anything that runs in the JVM or in .NET, for instance, as runtime type information is always available. C++ has dynamic_cast. What common language actually has parametricity expressed in the type system?
Saying Java doesn’t have parametric polymorphism because you can cheat is like saying Haskell isn’t pure because of unsafePerformIO.
This is a completely false dichotomy. Just because a feature can be misused doesn't mean it's not legitimately useful. Generics make the language easier for the user, but are harder for the implementors. Most language designers / implementors recognize that this trade-off is worthwhile, and therefore nearly every other popular typed language has them. The Go implementors are the only ones against doing it, because, well, they would have to implement it, and they're concerned that it will make the codebase too complex for them to maintain. (Their sympathizers are against it too, which is still a mystery to me.)