Hacker News new | ask | show | jobs
by sblom 1575 days ago
I struggled for years with a chronic misunderstanding of Go. I kept trying to compare it to the usual suspects in the "next systems language" crowd (D, Rust, Zig). That wasn't quite right.

Once I realized that its sweet spot is large-ish services that you want closer to the metal than Java but for which would be silly to go as low level as C++, Go fans started making a whole lot more sense to me.

I'm still not a Go fan personally—my taste in programming languages slants toward the more expressive end of the scale (C#, Rust, Scala). But at least I'm no longer confused by trying to make Go make sense where it doesn't.

It's a very good tool for its kinds of jobs. Other languages also have their points of unreasonable effectiveness, too.

7 comments

> Once I realized that its sweet spot is large-ish services that you want closer to the metal than Java but for which would be silly to go as low level as C++, Go fans started making a whole lot more sense to me.

Yep. I struggled and then I realised I could efficiently convert a complex shell pipe with a set of frustrating-to-the-customer prerequisites into a single, easily compiled cross-platform binary, and that it was really like Modula-2 and Occam to do it.

That's the point I became a fan.

Rob Pike actually defined it exactly this way when it was introduced -- a simpler systems language, in contrast to Java.

It's funny -- I actually just watched this video yesterday: https://www.youtube.com/watch?v=5kj5ApnhPAE

Wasn't Go essentially Limbo from Bell Labs, like Rob Pike and others who moved to Google?

https://en.wikipedia.org/wiki/Limbo_(programming_language)

Go is like what C++ should been long ago, from the creators of C.

Ditto with plan9/9front and the original Unix.

Now, QT/C++ is the new Motif/C, but not just for Unix, but for doing cross plataform tools everywhere.

I think the future will be shipping static Go binaries with GIO everywhere.

INB4 "disk space", today's compilers and linkers should strip away all cruft from linking by removing any useless library function.

> I think the future will be shipping static Go binaries with GIO everywhere.

I would like to add a GUI to a little (very little) mysql database updater tool I have in customer hands. GIO is interesting and impressive but I am not as optimistic as you that it will develop into anything big.

Limbo + some touch of Oberon-2
Is Java really a systems language?
"systems language" and "systems programming" are terms whose interpretations vary widely across the industry. At one extreme, it means kernels, drivers, and embedded, the stuff where you need to precisely manipulate bytes with no infrastructure and minimum overhead. At the other extreme, it means any software whose users are other programs rather than people, so API services and so on. My first job was as a "systems engineer", writing database middleware (kind of) in Java.

Go is not suitable for the kernels etc kind of systems programming, but it's highly suited to the API services kind.

In fact, the terms are becoming more and more diluted. "Systems Engineering" is a good example; it actually used to be a well defined discipline (see EIA-632, IEEE 1220, ISO 26702, etc.) until some non-US universities started to use the term for disciplines like system administration or computer network engineering. Similar confusion e.g. exists on the question of whether C is a high- or low-level language. The funny thing is that Go is even used as a low-resource embedded system programming language, e.g. for the micro:bit.
Maybe it's a regional thing, but I don't know anyone who calls that "systems programming". I'd personally use the term "backend programming".
That's not what I said. Pike described golang as a systems language, and specifically contrasted it with Java. Perhaps you should watch the talk.
> That's not what I said.

Okay, but it's a pretty reasonable interpretation, right?

"Simpler X, in contrast to Y" makes it sound like Y is a less simple X.

So another way of saying this is consider the space of languages where

* control over memory use and layout (in contrast java is a pig over memory usage)

* some kind of easy way to use multicore (goroutines with channels or something else)

* speed, good cpu utilization

* garbage collected for ease of use

How many mainstream languages actually fit these criteria when Go came out? None? And how many fit these criteria now?

Go was definitely ahead of the curve on a few things.

I'd argue C# was there (or very very close). C# has had value types (and fine-grained memory layout) since the beginning, reified generics since .NET 2.0, and also (lesser-known fact) raw pointer support (inside `unsafe {}` blocks much like Rust's approach). This was all motivated by interoperability with native code (mostly Win32 or other C-like ABIs & COM).

In 2009, the concurrency paradigm in .NET was more like promises and not quite as slick as goroutines. async/await wasn't born until 2012.

It wasn't on your list, but I'll toss in another point that works in favor of your original claim. ;) The main C# project also wasn't TRULY multi-platform until 2014.

To be fair Java has made some strides in memory usage. GraalVM reduces it a lot and with Valhalla (and to some degree Loom) it should be more competitive on that front (and others) with other languages.
I'd like to add the recent addition of ZGC as a massive benefit the JVM. Pause times always measured in microseconds regardless of heap size. No other GC:ed language has that capability as far as I know.
As far as I am concerned, Go feels like an attempt to write a systems-oriented Python. Or perhaps a systems-oriented language targeting Python developers.

It's a very reasonable objective. I just happen to not be in the target audience.

Go felt to me more like improved C with GC - not surprising when Ken Thompson and Rob Pike are involved.

With Go you are going to be writing a ton of very explicit for loops. The error handling also feels a bit weird.

To me it seemed like a regression not to have map, filter, apply, reduce. I wrote my C for loops in the 90s!

To me something like Scala feels more Python like.

Both can handle similar data munging and ML tasks. Interfacing with DBs(relational or otherwise) again I'd take Python or Scala over Go just because of convenience factor.

I suppose it is also question of libraries. I've grown too comfortable with the vastness that is in pip or maven. By comparison Go library landscape is relatively bare.

Then again those native binaries of Go are so appealing...

The funny thing about Go is how many different things you can recognise in it.

I have a little C experience (in the distant past -- PVM, lex/yacc, Xview). I also have a little Occam and Modula-2 experience. Lots of Java and from then on a bunch of less comparable interpreted languages.

Go feels idiomatically more like a Modula-2, Wirth-language expression of Occam to me than C.

I like an awful lot of it.

> The error handling also feels a bit weird.

I think it is deliberately weird; it is designed to make you consider error handling right up front, which is where the "system language" thing comes in. No cascade of exceptions.

I think that's pretty much aligned with Google reasoning back then. Go was designed to make it easier to onboard their fresh grads + scientists hiring,which were more familiar python to do systems stuff.
Yes, there is a well-established PHP to Go pipeline among developers.
Here's where I've settled at; Any web services for which I used Java, Python before is now written in Go. The productivity(Easy to write/read) & Cost(Concurrency saves $ at scale) improvements makes it hard to not use Go here.

Then what about those sweet web frameworks for Java and Python? Go makes it easy to write web services without relying on 3rd party frameworks but it does involve a learning curve which is not steep, There are some great examples[1] and thanks to readability one can learn what's happening even if they're just starting with Go(From other languages).

That said, I haven't had good experience with Go on low-memory environments even at 1GB, Perhaps it requires more thorough optimization in the code reg memory usage(which defeats the aforementioned productivity) and naturally a non-GC systems language like Rust might be better suited here.

Then I recently started experimenting with Go-WASM and found that the initialization less-intuitive(requires runtime wrapper), Compiled size is humongous and Go's concurrency prowess unavailable[2]. Another area where Rust seems to be a better fit but hoping that Go becomes better here, I don't want to use 4-5 different programming languages to build a single web application.

[1] https://github.com/fragmenta

[2] https://news.ycombinator.com/item?id=30356020#30357078

Define "closer to the metal than Java". What exactly does that mean, and how exactly is that an advantage?
Two major things:

1. It compiles statically down to machine code; there's no JIT or bytecode interpretation execution path.

2. It offers straightforward control over the memory layout of your data structures (it doesn't offer straightforward control over the lifecycle of your memory, which is the next step towards the metal that Rust takes).

The advantage is that casual Go code is generally going to be more efficient both in execution and memory usage than a casual program in a higher-level language. You can make Java do almost anything; the important thing is what languages make easy, not what they make possible.

When the actual machine code is generated is irrelevant to the level of abstraction. There have been JIT compilers for C, and ahead-of-time compilers for C# and Java, and that changes nothing about how close to the metal any of them are.

Memory layout is a valid point though. C# with its value types gives you a lot more control than Java does, but is still often grouped with Java, and I think rightly so. Go's pointers go quite a bit further, but then on the other hand, it also has high-level data structures like map as language primitives, which makes it less close to the metal as far as I'm concerned.

I'd personally group all GC'd languages in roughly the same class here, but I think it's reasonable to disagree or make finer distinctions.

By that logic, every language is equivalently close to the metal when it comes to execution, since they can all be JIT'd one way or another. It's a colorable argument but not one most practitioners would agree with.
No, I would agree that something with a smaller runtime might be considered closer to the metal, I was talking about level of abstraction, which I think is different. One example is that a typical C code that depends on a libc is farther from the machine than C code that runs without a libc. Both might use very similar styles.

I'm also not saying JIT vs. AOT is an irrelevant distinction in practice -- like everyone else, I like my programs to start fast. But in the end, you have machine code in RAM either way; the level of abstraction is, all else being equal, the same.

The precise details of how that machine code gets there change nothing about how the program is written. The emphasis people put on those details aren't always warranted. I don't think they matter at all for typical backend code, which is one of Go's main niches.

Edit: The earlier version of this response was maybe unnecessarily pointed, I expanded and toned it down a bit.

The one significant thing i can think of is that Go makes pointers explicit, and allows variables and parameters which are by-value. So you can control whether some struct contains a pointer to some other struct, or just embeds the fields directly. This gives you influence over memory use patterns, access time, and garbage collection that you don't have in Java.

Java is planned to gain an equivalent of this ability through primitive classes (JEP 401). As as i know, we expect to get a preview of this feature in Java 19, which should be released in September this year.

Go does not have bytecode or a VM, it compiles directly to a binary with a runtime.
Java (and C# I believe) can also compile to binaries. And golang has a runtime as well.

Now what is the advantage again? The Java can compile to JVM bytecode and be better performing than golang, all while having superior introspection and monitoring and debugging abilities. It seems to be a win-win. Only some ideological "closer to the metal" philosophy doesn't apply, so what?

If startup times are truly an issue, look at Quarkus[1] and Micronaut[2], and a lot of other frameworks that use GraalVM to compile to native binaries.

[1] https://quarkus.io/ [2] https://micronaut.io/

I am mostly a Java guy, but when people claim that Java can also compile to binaries, I really don't like that.

It's kind of true... but with so many caveats it's almost a lie.

* it compiles so slowly even basic applications can take 10 minutes to compile. What the hell are they doing all that time?!? Go can compile to multiple OSs architectures on the same machine and it takes a couple of seconds even for large code bases!!

* you can't use most of the Java ecosystem as reflection is endemic... good luck manually declaring everywhere reflection will be used.

* the loss of the JIT hurts peak Java performance a lot. Java runs as fast as Go *once the JVM is warmed up*! Native-image peak performance tends to be some way behind.

Not saying GraalVM native-image is useless, it can be used if you have the energy and knowledge to get past the issues... but as someone who konws Go as well as Java, if I am going to the trouble of going native, I'd just use Go without a doubt.

Also good luck if you need to cross-compile. The Go toolchain for that is seamless, Graal’s is non-existent (because it is fundamentally incompatible with the way native image compilation works).
If you are cross compiling while using Java, you really don't get Java.
So you are a Java guy and are only aware of GraalVM, while ignoring all the AOT commercial offerings since 2000?

ExcelsiorJET, J/Rockit, Websphere Real Time, PTC or Aicas aren't GraalVM.

Also if you don't want to lose JIT, while having the advantage of AOT compilation, JIT caches are a thing, nowadays available for free on OpenJDK, OpenJ9 and Android (even though it isn't proper Java).

I've been working with Java since 2009 only... those things you mention have never been used anywhere I've seen since then (but yes, I heard of them as things of the distant past that no one used).
No one insulted Java. Why so defensive?

Go and Java make different tradeoffs. If you're unreasonably effective in Java and its tradeoffs work for you, that's completely fine. If you have good tools that make Java more like Go when you need Go-like characteristics, that's cool too.

I'm pointing out the inconsistencies in golang fans arguments which I've seen from the very beginning since it was touted as a "systems programming language" (which has been more or less silently changed since it wasn't true, but it doesn't stop the fans from parroting it). Same goes with many other false claims about the language, which aren't just non demonstrable, but demonstrably false.
Relax. Many people would call Docker/Kubernetes, and various types of databases like CockroachDB as systems. Lot of enterprises call large internal applications as "systems" There is no copyright on "systems programing" and it can be used only for OS kernels and such.
Java does not perform better than Go, they're pretty much on par but I would say that overall Go is faster. As for the tooling that Java has those it's because the language and runtime or so complicated with many layer of abstraction that you need those.

Go has pretty good introspection with pprof it's enough, you don't need something heavy like JFR. For debugging delv is ok, not on part with C++/ Java but it's fine, you can even do remote debugging now.

The thing is with Java and to some extend C#, yes they have different runtimes, VM, AOT / JIT etc .. different thing to compile to native binary: none of them are really mature atm and moreover it's even more complexity for the programmer, now he has to choose which runtime or compiler he's going to use, it's crazyness. Same story with the GC Java offers, too much choice, too much burden on the programmer. For app A you're going to use this GC + runtime, app B is going to be different, it really mess up the dev / ops process.

> Java does not perform better than Go, they're pretty much on par but I would say that overall Go is faster.

Real world programs disagree. And for any large program, the JVM is a superior optimizer than golang's compiler.

> As for the tooling that Java has those it's because the language and runtime or so complicated with many layer of abstraction that you need those.

I heavily disagree. I deployed services both in golang and Java/JVM languages, and simplicity of the language or runtime has nothing to do with the JVM having superior observability and monitoring.

> you don't need something heavy like JFR

I wonder why my employer is spending millions of dollars on dev salaries to build something not even remotely comparable to the JFR for their golang programs then.

Secondly, the JFR is extremely light weight, and gives you < 1% overhead at runtime. Show me another ecosystem that gives you this out of the box.

> Same story with the GC Java offers, too much choice, too much burden on the programmer.

It doesn't really. The newer GCs have very few knobs to turn. Compare to when you hit GC issues in golang, the solution is to rewrite code in nonidiomatic ways as we saw with Discord. The first approach is superior.

I urge you to look into Javas new ZGC. It's a massive achievement, having only <1ms pauses even on TB sized heaps. Go:s GC can't hold a candle to it in terms of low consistent latency.
> As for the tooling that Java has those it's because the language and runtime or so complicated with many layer of abstraction that you need those.

Sure, Java has much more need of dev tooling than Go. But the available dev tooling on Java being enough better than the Go tooling to make the language + tooling have a better DX can still (if that is one's experience) be a valid advantage, for anyone not working in an artificially constrained environment where they are forced to code with Notepad and no tooling.

99% of people run Java on the JVM. Just because you 'can' compile java to native code doesn't mean it really applies in real world situations. Plus as far as I can tell the only compiler that can compile Java to native code (GCJ) is no longer maintained.
PTC, Aicas, WebSphere Real Time, GraalVM, OpenJ9.

Additionally, JIT caches are now part of OpenJDK, OpenJ9 and ART.

Nowadays people use GraalVM Native image for AOT compilation.
It's true. Go is basically Java/C# with its runtime baked into the binary. Also, it's only marginally faster than Java.

I never understood Go. I was sold as the C killer and failed, now it's basically an alternative to Erlang/Elixir, but suddenly people started running around and saying "Noooo, it was never meant to be a systems programming language like C!!!"

golang is not marginally faster than Java however in the real world.
Golang can usually more than halve your memory usage? The economics may dictate something more like golang.
What does that have to do with being "closer to the metal"?

Secondly, Java can be tuned, but its default mode of operation is to take up the most amount of memory it can in order to give you higher performance (thoughput and latency). `-Xmx` is a thing.

Finally, now with GraalVM going mainstream, and frameworks like Quarkus[1] and Micronaut[2], you are able to compile Java programs to native binaries and also have lower memory usage if that's truly a restriction.

[1] https://quarkus.io/ [2] https://micronaut.io/

You also asked what the advantage of golang was and I told you what the advantage was. I'm was not saying "closer to the metal" is the right description, but, if we'd stop being pedantic, I think we know what she/he meant.

Some people really don't want to tune VMs. No one is saying Java doesn't have a place too. Jeez, dude.

OK -- but you've listed a whole bunch of third party projects and technologies and tools to get Java closer to what Go does _really_ easily out of the box.

I like Java (used to _love_ it about 26 years ago... been a decade since I've written any) but Go is actually a breath of fresh air for typical cross-platform systems programs.

Golang + UI should have trash JDK to the trash of the history long ago, but people never learns, they are blinded by the Enterprisitis.

Ironically Sun invented Java because lots of people bitched against TCL's non GPL license. Ironically, TCL/TK since 8.4 ran much snappier and faster than any Java turd even in 2004. Even simple Java 2D indie games looked laggish against AMSN, which was a "biggie" TCL/TK MSN clone back in he day.

Ahh, Golang UI stuff... now that is a dark alleyway!

But I think Java comes from something rather older, designed for interactive television, way back before anyone outside CERN had really seen a web browser. In that way the JavaStation is philosophically much closer to the roots of Java than the Java applet.

GraalVM is not third party.
What are those Java framework turds like Quarkus, that you keep bringing again and again?

Also GraalVM is not 3rd party but also not OpenJDK. It is Oracle product and where many perf related features are only in enterprise version. Also it does not support most of JFR JVM monitoring.

I am perfectly fine people/companies paying for performance. But it is not like Native image is trivially applied to any existing Java project. Either one has to use limited frameworks that you keep listing or spend endless hours in generating native json files to cover reflection cases.

"Go performance is excellent since Go compiles to bare metal and there is no runtime between the metal and the language as is the case in other languages I used in this exercise (Java & Clojure: compile to JVM bytecode, and JVM runs the bytecode, Python & Javascript: interpreted languages and the runtime runs the code (though also Python compiles to bytecode)."

Source: https://www.karimarttila.fi/languages/2018/11/13/go-good-pro...

That statement is misleading. You can also compile Java natively. Secondly, there is most definitely a runtime "between the metal and the language" in golang, the GC being the most obvious.

This proves my thoughts that these claims are not valid.

>You can also compile Java natively.

This is also misleading. You are implying that GraalVM isn't relatively new and that Java native compilation isn't rare. I've yet to see anyone deploy service or CLI tools that are natively compiled in Java. That statement is about as true as saying you can compile Python natively. Just because its possible doesn't mean the language is actually suited for it.

I never said it was rare or not. It is possible if you truly need fast startup times. The fact of the matter, the JVM is good enough for the vast majority of the use cases, and is faster than golang so no need to even go there.
>, and is faster than golang

Nice joke. Go software runs much snappier and faster than any Java GUI or CLI tool.

You weren't looking into the right plaaces, ExcelsiorJET, PTC, Aicas, Websphere Real Time, Android since version 5 (althought the story here is complicated).
>That statement is about as true as saying you can compile Python natively.

Python is actually compiled. When you run a file, it firstly compiles the cod into a bytecode, which is saved in ‘.pyc’ files. These are afterwards interpreted by the interpreter.

So does TCL, and yet Go outperforms TCL/TK, even 8.6.
Call me when I can compile some static binary for Windows from OpenBSD such as GOOS=Windows GOARCH=arch32 go build foo.go.
There is a runtime between the metal and the language. The runtime is what makes it really nice for writing network services in. It's also what makes it really terrible for lower level things.
It wasn't claimed to be an advantage I think. It's a tradeoff.
A tradeoff in what exactly?
Shipping arch / OS / runtime vetsion neutral apps vs implementation simplicity and single file binaries, for one.

Also, decoupling of the runtime from the language is huge, and lets us have nice languages like Clojure and Scala on the JVM.

you aren’t closer to the metal than java