Hacker News new | ask | show | jobs
I want off Mr. Golang's Wild Ride (2020) (fasterthanli.me)
114 points by archenary 1987 days ago
16 comments

The most insightful way I've ever heard Go described is as a "C fanfic". It's like a bunch of C programmers, writing software for web infrastructure, got together and made a wish-list of things they wanted to be different about C (specifically in the context of writing web infrastructure). And then they made a new language, taking the most direct path toward that wish-list, and inheriting most of C's other traits as a matter of course.

Taken in this light, Go makes a ton of sense. No undefined behavior! Well-defined zero values! Duck typing! Automatic memory management with minimal overhead! Easy-to-use threading primitives and trivial cross-platform builds! A networked-C programmer's dream.

But we've learned a whole lot about language design in the past 40 years, and combining those things we've learned with a loosening of C's constraints, there are much better fundamental design decisions that can be made for a greenfield language. It just seems like Go's designers weren't really interested in questioning a bunch of the ones they were used to.

Exactly

Go can be understood as an improved C that keeps much of C's simplicity but adds small, powerful features like interfaces and channels and garbage collection

Go fixes C's well-understood flaws (declaration resembling use, unintuitive operator precedence, unrestricted address math, silent casting, zero-terminated strings, etc.)

Go puts essential C idioms directly into the language (pointer/length is formalized as slices, packages are part of the language instead of just being naming convention, etc.)

The longer I used C++, the more I despised it. I used C++ for 11 years and I literally hate the language. But C has always remained a pleasure, and Go is a continuation/modernization/enhancement of that

If you like C, you will love Go

It's a feature for sure. The article was a refreshing read too! Of course, hiding and abstracting away much of what is available in C, will have issues when you have special needs. But it beats "make configure" any day, and works well when you just need something with decent speed and memory footprint to get the job done.

I'm enjoying all of what you mentioned above, and dislike languages that are more C/C++ like now, as you often get "un-bit" by these snags using Go. However, Go has some snags on its own (hello slices!), so it's good to make sure one learns the fundamentals and what works well. A bit sad when repos import hundreds of other packages, I just turn away from such offers. It's been the state of IT for past 20 years that everything is essentially garbage. This is nothing new, and one just need to pick one's poison as you go along.

Nothing is ever simple either. All the "better solutions" in Rust, is sure to need refactoring and updates, while Go-code can mostly continue to run as-is. That's a good aim for its niche. Though, we all know the underlying platforms are very diverse, complex and come with snags of their own. I don't think the aim of Go is to tackle them all like "make configure" attempt to though.

I'll be happy to learn Rust for some herculean effort sometime.

Thanks for your comment

Picking up on one of your snags, Go's slices will "click" for you once you start thinking of it as a pointer and a length (and a capacity), but nothing more.

Realize it's just a C struct like this, passed by value:

  struct intSlice {
      int* addr;
      int len;
      int cap;
  };
The memory at addr is not owned by the slice. All the slice operations are simply notation for manipulating the struct. Go's garbage collection makes the whole thing work brilliantly

This can be confusing if you're used to std::vector (which owns the memory) or python's slices. Go's slices are a shallow pointer/length system exactly like is used in C all the time. For example:

  void sort(int* addr, int len);
becomes

  func sort(a []int)
A Go slice is just a pointer/length, with terse notation
For me I just use what's available and do not go into too much detail beyond what I need. However, slices can be confusing at first, and your above example could help think of them the right way. Although, until you get "bit", you might not deduct the consequences of slices right away. Especially when accustomed to other languages.

The latest thing that made me go "hmm" last time, was this one (I didn't get "bit", just went "hmm" reading it):

https://play.golang.org/p/2bTvXr6WLNN

  package main
  
  import (
   "fmt"
  )
  
  func main() {
   b := []byte{'g', 'o', 'l', 'a', 'n', 'g'}
   fmt.Println(string(b[1:4]))
   // Output:
   // ola
  }
I'm sure everyone expected this output when using b[1:4], right? All languages do these things a bit differently, so is why I always forget the detailed syntax required. I'm sure there's a valid pragmatic explanation and there's lots of ways to do this (ie. allow negative values etc.). Just a thing that while speedtyping, one could easily miss this little detail.

This one is a good intro, but doesn't explain this I believe:

https://blog.golang.org/slices-intro

I honestly think of Go as Java with an appeal to C programmers. And of course much better performance/memory usage than Java.

Go is a high-level language. It is not meant for low-level programming. and yet the authors keep claiming that it is.

Wow, this is an excellent critique. I don’t expect any language to be perfect, so I’m personally alright with my investment in Go. Nonetheless, I love when people share the ugly parts of software so clearly so I can anticipate and avoid similar problems. Since I use Go, I actually got a lot out of this and enjoyed reading it a lot.

Go’s simplicity scared me a lot from the outset - there is no free or easy solution in software. Everything is a trade off. As such, I think Go is an excellent tool for prototyping dumb solutions for relatively simple problems. Or at least, for modelling solutions around simple parts of problems while ignoring complexity until later. On our team we see anything important as something we finish fast with Go/Python, then we do it right with Rust when we fully understand it.

As a tool for getting things done quickly with that pretence, I’d argue that Go is an awesome tool. I would be afraid of building something large and expected to live a long time with it, though. Anyone who has worked with software for a while should be wary of any solution that claims to be simple.

Anyway, I really enjoyed this but wanted to point out what I like about Go.

I don't think Go lies about what it is. It is just a victim of its popularity.

The authors clearly say that is designed for writing scalable networked services. And they definitely don't care about GUIs, Windows, embedded, etc.

Overzealous programmers are constantly taking Go where it is not meant to be and complain about its shortcomings. Go's simplicity means that it makes a lot of assumptions about the system. I think authors should have been more upfront and explicit about this.

> Computers, operating systems, networks are a hot mess. They're barely manageable, even if you know a decent amount about what you're doing.

No, they are not. It is extreme incoming flow of poorly trained workforce with no relevant experience making it so.

You don't need to know a lot about networking if you don't use microservices, but you just cannot build a decent future proof monolithic system with adequate deploy cadence if you have a team of 50 python devs fresh from coding bootcamp.

You can abstract your OS away and actually don't need a file system at all if you follow 12-factor methodology.

I can rant forever about this, but all this boils down to one thing: fundamental and systematic knowledge of CS and software engineering beats any new fancy tech. While again and again investing one's thousands of hours into new languanges and frameworks — one is doomed to just repeating one's mistakes.

Great article! Really enjoyed reading.

It does seem that golang is well suited as a language for backend services running in an Unix environment and I think that’s an Ok trade off for a language to make. It’s okay not to excel on everything.

I don’t think this should surprise anyone. Go is an excellent language for quick prototyping and easy distribution.

The investment to become fluent in Go might literally be an order of magnitude less than becoming fluent in rust.

Rust might be the perfect language in terms of capabilities and safety, but it is far from a simple language.

The function signatures from even some simple methods have become ridiculous. I’ve seen enough examples where it was needed to unpack a value two or three times to get the value you want.

The perfect language probably doesn’t exist, but go is one of the easiest compiled and strongly typed languages to learn. And that in itself is quite an achievement.

> The investment to become fluent in Go might literally be an order of magnitude less than becoming fluent in rust.

From my own experience with both languages, it's actually closer to two orders of magnitude. One order of magnitude might be correct for the language, but Rust requires you to navigate the ecosystem very early on [1], whereas Go gets you much farther with its stdlib in its common usecases.

[1] For example, you pretty much immediately have to decide "Tokio vs async-std vs std" if you want to do anything with IO, or "Actix vs Rocket vs whatever" for HTTP, at a point where you probably cannot gauge the ramifications of these choices properly.

Anecdotal, but I've found rust much easier to grok and become comfortable to work in than I have with Go - partially due to the docs, but largely because of the perceived complexity in explicitly typing and handling of options and results.

With rust, I very rarely feel like the code I'm writing might not be correct for a technical reason, whereas with Go, I find myself very often having to think too much about how best to actually do something "safely" or "correctly" because it's inherently possible in a way that rust makes either impossible, or at the very least, warns you profusely.

Isn’t having to check for integer overflows in rust an example of the exact opposite of your example, or is this something that requires extra effort in go as well?
You don't have to check for overflows in rust? It does by default in debug and not in release and has five explicit adding methods for any of the ways it could behave
I tried learning go a few times years ago but got stuck with tooling issues and when I made it to work I was put off by the syntax / verbosity, error messages and never managed to learn it.

I started doing a project in rust and things just made a lot of sense (with previous haskell, C/C++, JS experience), fixing compiler errors until green was easy. Eventually I developed an understanding for fixing lifetime related issues, which is the only complicated bit in rust (and hard to fix ones are not even that common).

I'm definitely more confident in the correctness of my programs written in rust than anything else - even than haskell, my previous gold standard experience, given the lack of GC and laziness.

I think different people will grok different languages.

From a maintainability point of view, from what I experienced in a few companies, most developers will not feel comfortable with either go or rust.

The situation around alignment of integers for atomic operations is unfortunate. I think the cause for it is that they need to use a 4-byte alignment of int64 on 32-bit platforms to remain compatible with C when using cgo. Using an 8-byte alignment is also wasteful, considering that 4 bytes are sufficient and 64-bit atomic operations are relatively rare on 32-bit platforms.

One way to fix this would be to add a special language keyword to increase the alignment, but that feature doesn't really carry its own weight in a language like Go. In my opinion, life would be better if the atomic package didn't allow you to apply atomic operations against raw integers, but had its own boxed integer types that were guaranteed to be properly aligned. I implemented exactly this, because I also got bitten by this more often than I would like:

https://pkg.go.dev/github.com/buildbarn/bb-storage/pkg/atomi...

Now I don't need to worry about that problem anymore. It's annoying that the Go developers focus on stability so much, that the standard library hasn't really evolved a lot since 1.0, which seems to be main source of frustration for the author of this blog post.

What I do appreciate about Go is that cross compilation is pretty good, and the runtime environment also works pretty well. Some time ago I wanted to mmap() some file and also deal with page faults properly (e.g., in case of I/O errors, truncations of the file that's mapped). It turns out that Go can do that really well. Sure, you can install a signal handler for SIGSEGV in C and Rust, but the mechanics behind tend to be confusing.

Happens over and over again. An overly simple abstraction makes building toys easy but makes building real stuff much harder than an abstraction which accurately reflects the complexity of the underlying domain. Complexity cannot be destroyed, it can only be managed. Go tries to hide the complexity of file systems, networks, dependency management under a rug.. predictably it blows up.
A compelling critique that Go's embodiment of the "Worse is better" philosophy from Unix is to its detriment.
As someone who programs in both Rust and Go, I wish that Rust developers would put more effort into improving the Rust ecosystem than complaining about Go.

Languages are tools and not tribes.

> Languages are tools and not tribes.

That's incorrect.

The tribe is the more important feature than the programming language.

C became the tribe of "systems programmers". Lisp rose and fell with the initial tribe of AI. Perl was the tribe of the system administrator and fell when they did. Ruby rose and fell with the tribe of Rails. Python is riding the tribe of numerics.

The language needs to at least be not actively hostile to the tribe, but after that it's pretty irrelevant.

From reading the blog, he only started getting into rust because of issues with Go, so this seems a pretty unfair criticism here.
Another day, another repost. It's a great article, but at some point it should be given a rest.
Is this an issue with Go, or a particular praise of Rust? The article mentions NodeJS has similar issues, now I'm curious what other languages do for these API, is Java or Python any better?
Surprisingly, this post made me really appreciate Go. I thought it explored solid design decisions towards simplicity, such as UTF-8 only.
The issue highlighted, at least for UTF-8, is that Go just _assumes_ everything is UTF-8. It makes seemingly no effort to actually _enforce_ UTF-8, leading to silent mistakes like with the file path.
Yes, that _is_ surprising! The points made by the OP are exactly the opposite. I believe the language itself is redeemable, but it's the implementations of many features that are just so faulty.

To take your example, yes it's great that it makes UTF-8 as the primary encoding for strings, but then the implementation in the core and in the ecosystem completely fails in enforcing or honoring that.

Edit: please see the filename example in the post to see the failure around adhering to UTF-8.

I have turned this comment into a blog post: https://news.ycombinator.com/item?id=25618264

It is a well written and in-depth look at the rot inside the Golang ecosystem. Make sure to read to the end and notice that the rot started at the core contributors level.

Golang's tagline, from their [repository][0], is "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software."

Reading this post by Amos should make it clear to you that Golang has succeeded ONLY in the "simple" part of the claim; unless written with extreme care, programs written in Golang are neither reliable, nor efficient.

Amos presents some examples of why I have disliked Golang since the beginning. After having used Golang for a few years seriously, I disliked it enough to start a fork of the language named [GoFY][1]. I named the language as such because, since the beginning when I saw some of initial presentations by Rob Pike specifically, and some others' presentations and blog posts generally, they had an air of ego when dismissing others' opinions and concerns, and appeared to say "these are our decisions, that is how it is, and if you don't like it, Go F* Yourself". So the project name was a GoFY to them back, from me.

I'm sure it looks a great language from afar, and for newcomers. But as a seasoned developer who has seen a few other languages in thier lifetime, you will quickly begin to see the problems with the language and the ecosystem around it. The astute among you may notice that in my [post yesterday][] I did not claim to be an expert in Golang; it's hard to be an expert in something that's fragile, flaky and full of special cases. For the same reason I never took up using MySQL; I have heard enough stories of its flakiness and special cases that it never looked like a solid technology to me. I openly and whole-heartedly recommend learning and using [Postgres][] to anyone who would listen.

[post yesterday]: https://gurjeet.singh.im/blog/persistence-perseverance [Postgres]: https://www.postgresql.org

Fortunately I did not invest any more time in it other than to document a few times in section ["GoFY Desired Differences"][differences] as to what I would like to see different in the GoFY language, which in turn would make it better than Golang, at least for long-time systems developers like myself. I am glad I didn't burn any oil on it because creating a new language, even a fork, is neither easy nor quick.

[0]: https://github.com/golang/go [1]: https://github.com/gurjeet/gofy/tree/gofy [differences]: https://github.com/gurjeet/gofy/tree/gofy#gofy-desired-diffe...

> "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software."

This claim is mostly accurate from my experience if amended to "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software as long as you don't do stuff Rob Pike didn't expect."

I'm going to count "run on Windows" and "have non-UTF-8 filenames" among these.

As a systems developer with 20 years of experience in a variety of languages, I share your general frustration with Go. But I don't agree with any of the changes you suggested in GoFY.
Hey I saw a post you made about dmt and tinnitus. Same thing happened to me a few weeks back so I was researching to see if it gets better. Does it ever get quieter or will I have to hear through a ringing forever???
Interesting. Certainly it doesn't bother me anymore a couple years later, but I don't think it completely went away.

I was still never sure the dmt caused it so I would be interested to hear your story. Maybe email me? dev@doubly.so

Are you particularly proud of this GoFY episode? I mean, being all talk and no follow-through is ten-a-penny.
Wow, inconsistency across Operating systems "papered over" to look like Unix everywhere and a library importing the world is enough to make you think Rust is better than Go?

Yikes.