I don't understand what "industry purposes" means and in what aspects Java is better than Go in your opinion (I can think of some myself, but I'm interested in your perspective).
I don't understand what "industry purposes" means and in what aspects Java is better than Go in your opinion (I can think of some myself, but I'm interested in your perspective).
1) No immutable types. My work team is a huge user of immutable data stuctures in Java to make sure data passed around to other teams isn't changed. Go doesn't really have a good way to do this.
2) Refactoring can be really annoying (or at least really noisy) because of public/private being defined by capitalization of method/field names.
3) Error handling isn't great. I love Go's errors being just normal values, but the `error` interface is awkward when trying to figure out what kind of errors can be thrown without having in-depth knowledge of the kinds of errors that can be returned. We regularly need to make different decisions depending on the kind of error returned. Knowing which errors can be returned in Go is not defined by the method being called (only in comments).
The typical answer is opaque types with only readonly methods exported. Not elegant, but it’s there. I guess it’s arguably not a “good way” to do it.
Bit of snark from my side, but that's exactly what makes it less good of a fit for "industry purposes".
Go's error handling is possibly the worst out of any "modern" language, it basically copied C's errno which is not something you should have ever done.
E.g. if I do some IO like "make a copy of these files" and get an error/exception, it's only the caller or maybe even that caller's caller that can properly deal with this condition (e.g. to decide that we will skip the erroneous files or retry).
- Java is a high-level, multi-paradigm programming language
- Go is designed as a systems language to supersede C projects at Google
Now Go identifies as a general purpose language that competes with Java? It's a free country, I guess.
It is a language with a fat runtime, running a garbage collector. You just burn it into the binary and call it a day.
But burning a JVM next to a jar file is not hard at all, one could make something like cosmopolitan.
Actually no. Go was designed from the beginning as a systems language as a C replacement.
Go’s type system, for example, is very much a systems-language artifact. The designers chose structural typing because it was lighter weight, but provided enough type safety to get by. It sucks though for enterprise app development where your team (and your tooling) are desperate for nominal typing clarity and determinism.
But where do Go's docs or founders call it a C replacement? gf000 asked where this is mentioned besides marketing, but I don't see it in the marketing either.
https://web.archive.org/web/20091113154831/http://golang.org...
The main page title *Go: a systems programming language*
It still sports all the low-level stuff too, pointer arithmetic and all.
But then just stay truthful, otherwise C# is also a system PL.
Go's runtime is thin: goroutines, a GC specialized for concurrency, networking, and little else. Java, by contrast, assumes a JVM plus massive stdlibs to handle everything from enterprise apps to big-data, making its platform genuinely "fat" and layered. Other Java-tier languages, C# included, follow the same model.
also has modules now.
Go happened to be attractive for web backends too because it had good greenthreading before Java etc did, and better performance than JS, so it makes sense that they changed the marketing.
It's easy for the USER to fix, since there are flags available. In the day of LLMs it's also easy to find out about those flags and what they do. And if it's so important, testing shouldn't be supremely hard, either.
Normally when you run a non-Java binary, it uses very little memory to start, doesn't have a limit, and returns memory to the system when it frees things. Supposedly you can set JVM flags to do all that, but performance probably suffers, otherwise they would've just done that. So in practice users are always setting the flags carefully.
In Go, what gives is goroutines have to use some of their time slice to assist the GC and pay down their allocations.
In Java, I believe what you used to get was called "concurrent mode failure" which was somewhat notorious, since it would just stop the world to complete the mark phase. I don't know how this has changed. Poking around a little bit it seems like something similar in ZGC is called "allocation failure"?
The GC assist approach adopted by Go was inspired by real-time GC techniques from the literature and in practice it works nicely. It's not perfect of course, but it's worked just fine for lots of programs. From a purely philosophical point of view, I think it results in a more graceful degradation under unexpectedly high allocation pressure than stopping the world, but what happens in practice is much more situational and relies on good heuristics in the implementation.
And of course it's getting value types now, so it'll win there too. As well as vectors.
So unless you claim that there is no software in Go/C# where the GC is the bottleneck, no, the problem absolutely doesn't solve itself.
I'm not sure it's even better than Java's, especially for modern ZGC (and you can choose your GC in Java). Definitely less configurable. I would say most of online comments about Java's GC are long outdated.
For example, in web servers a lot of work is request-response, so it's convenient to utilize generational GCs (so that each request data would fit into "young" generation). Similar to arenas, but without code changes. Go's GC is not generational though, so you should care about allocations.
https://codemia.io/blog/path/The-Evolution-of-Garbage-Collec...
How do I verify that they are actually better? Is the overall performance of my program better? Because that's what I care about. I of course do include memory usage in "performance".
At almost every other case: G1 (the default, just don't add any flags).
Do you want to trade off using less memory at the price of some throughput? Decrease heap size, otherwise don't add anything.
That's it, in most cases just use the default.
They are not. Feel free to look up literally any half-decent benchmarks. If Java's on par or better than any other language of note, check the memory usage. It's standard for Java to have 5-20x the memory usage for about the same performance. The memory floor also seems to be in the hundreds of megabytes. Ridiculous.
> For example, in web servers a lot of work is request-response, so it's convenient to utilize generational GCs (so that each request data would fit into "young" generation).
No, that's a job for arenas. Generational GCs are mostly a result of Java's limitations, and not a univerally good approach.
> Go's GC is not generational though, so you should care about allocations.
You should always care about allocations. In fact, the idea that you shouldn't is a big part of Java's poor performance and design.