4 ms·
> And yet the care and feeding (tuning) of the GC consumes countless millennia of human time per year. This is a feature not a bug. When I write C++ code I nee
by invalidname 2y ago
> And yet the care and feeding (tuning) of the GC consumes countless millennia of human time per year.
This is a feature not a bug. When I write C++ code I need to make a lot of decisions in terms of memory behavior that would deeply impact performance. I can benchmark locally but production is the part that matters and I'm mostly blind there. An observability solution might be able to detect problems if I used the default C allocator under the hood, but in that case my performance would also be terrible to begin with.
Java lets me detect production performance issues and even pinpoint them to specific objects in a shipping application. This can translate to feedback to developers that could be very valuable. But it also allows me to tune GC behavior in production to get better performance with zero code changes.
Furthermore, the object deletion cost is deferred so if your app works in performance peeks it can be very efficient assuming it has enough memory allocated to it.
The downside is that Java will probably always need more RAM than non-GCd languages (the amount varies). That's a reasonable tradeoff for most since RAM is still cheaper than CPU/GPU.
> But we've been promised the ultimate compacting pauseless GC for decades, and yet I see outage after outage of huge systems root caused to "look, we found a brand new way that the GC can explode (or just thrash) on us.
There is no "one size fits all". Java has such GCs but right now the default JVM ships with several GCs since every workload has different requirements. This means you need to tune it which is a challenge.
If you see bad performance and don't know what to do then I would blame your observability provider. Good ones actually provide recommendations on how to improve a thrashing JVM.
> One can make the case for which is better (well, least bad) of Java or C++ error messages, but neither can come close to Rust error message quality and cleanliness.
Rust is great. But it is a young language with less baggage. It has no binary compatibility to deal with and it doesn't offer many of the language features Java (or for that matter C++) have. Those are all good things for Rust, but I wouldn't build the type of apps I build in Java using Rust.
> Like I said I'm impressed that Java managed to make error messages worse than C++, but you can disagree.
I just spent 20 minutes the other day looking at 100 errors in std::vector which I didn't touch at all due to closing brackets appearing in the wrong place... C++ error messages are at a different level compared to Java. Maybe I'm too used to Java but I never spend time on these things and the IDE is fantastic at handling 98% of the stuff.
> Go is not my favorite language, but here I think it's better than Java. RAII beats defer, but at least defer makes the programmer add the cleanup at resource acquisition, not four pages further down, possibly behind a null pointer check in case the finally clause triggers before the resource acquisition.
Go was built for simple quick solutions at the system level. Typically in such cases you would need to handle the error as it happens.
Java was built for libraries/frameworks/APIs. E.g. if Spring runs into an error it can't handle it since it doesn't know whether you want to show the error to the user, recover, log etc. Throw is the only reasonable option. This lets me build a nesting doll of libraries and dependencies that can defer decision making and even add a systemic solution that eventually handles that. E.g. in Java I can define a recovery policy (retry/circuit breakers etc.) with an annotation and the system would handle all of that for me.
In a typical Java backend application I don't write catch at all. You let the exceptions propagate and then write error handlers at the top level to define behaviors for the system/user. This also makes tracking issues in production much easier as you get a clean stack trace that includes all the details you need to fix most issues.
- thomashabets2 2y ago> [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.