> [needing to spend huge amount of time tuning the GC] is a feature not a bug.

I think you missed my point about how Java differs from other GC powered languages in this regard. Mistakes in the Java language has needless cost impacts on the operational environment. In simple terms: it produces an needlessly large amount of garbage.

Java made decisions assuming (like I said) that "oh a sufficiently smart GC will automate that". And that was incorrect. If they'd known that was incorrect, then they would have made a different choice. Hence it's a mistake.

The ability to tune GC in itself is a feature, sure. But that's not what I'm talking about. I'm talking about language choices that made the problem orders of magnitude larger than it needed to be. Did you read the linked "Go Does Not Need a Java Style GC" (which, sigh, is now partially behind a "create an account"-wall).

> The downside is that Java will probably always need more RAM than non-GCd languages

I'm not worried at all about that downside. It's a trade-off. But I wouldn't call it a mistake or a problem.

> There is no "one size fits all".

That's my point. Largely there's no "one size fits all" exactly because of language mistakes. They thought there would be, and they were wrong.

> [error messages] Rust is great. But it is a young language with less baggage.

Sure, but that was not the topic. Java absolutely does not have "some of the cleanest error messages around". In my opinion/experience they're much worse than C++ error messages. And that's just about the lowest bar in the world.

Python error messages are also much better. I can't think of any (real) language, compiled or not, with worse error messages than Java.

> Maybe I'm too used to Java

And I'm used to C++ ones, and it's a factor of course. But 20-30 lines of "C#3 extends Foo<Pair<K#3,V#3>[…]" from the post was not hyperbole. I took three lines from an actual message and just anonymized the names (the names would not have helped you. They did not help me nor domain experts). I showed it to very experienced Java developers and they brushed it aside, asking instead to see the code. The error message gave them almost zero information about the root cause, which sounds similar to your C++ example.

> Throw is the only reasonable option

Well, that's a bit of circular logic. Throw is the only reasonable option because the API was designed such that it is the only reasonable option. And the language and the standard library steered the design that way.

In the post and not, I try to stay away from simply rehashing the decades old debate of exceptions vs return values for errors, but I do add the observation that every Java system I've seen has logs and/or graphs with basically (uncaught) exceptions per second. The other languages that have something like this are fundamentally different. I expect that kind of thing in Erlang, because it's part of the philosophy. But NPE exceptions in Java? That's basically "bugs triggered per second". It's not as simple as pinpointing a root cause mistake in Java language (or stdlib) design, but an observation that the outcome of these Java code bases are a buggy mess.

I know this invites "sounds like a skill issue", but you don't get to a large code base without that. Not for this definition of large. This happens with world class Java developers running the show, and it happens in corp drone telco industry code bases. It's a consequence of the language like buffer overflows and memory leaks are a consequence of using C++, no matter the skill.