Comment by Xeoncross
1 day ago
I know they say that your programming language isn't the bottleneck, but I remember sitting there being frustrated as a young dev that I couldn't parse faster in the languages I was using when I learned about Go.
It took a few more years before I actually got around to learning it and I have to say I've never picked up a language so quickly. (Which makes sense, it's got the smallest language spec of any of them)
I'm sure there are plenty of reasons this is wrong, but it feels like Go gets me 80% of the way to Rust with 20% of the effort.
The nice thing about Go is that you can learn "all of it" in a reasonable amount of time: gotchas, concurrency stuff, everything. There is something very comforting about knowing the entire spec of a language.
I'm convinced no more than a handful of humans understand all of C# or C++, and inevitably you'll come across some obscure thing and have to context switch out of reading code to learn whatever the fuck a "partial method" or "generic delegate" means, and then keep reading that codebase if you still have momentum left.
> The nice thing about Go is that you can learn "all of it" in a reasonable amount of time
This always feels like one of those “taste” things that some programmers tend to like on a personal level but has almost no evidence that it leads to more real-world success vs any other language.
Like, people get real work done every day at scale with C# and C++. And Java, and Ruby, and Rust, and JavaScript. And every other language that programmers castigate as being huge and bloated.
I’m not saying it’s wrong to have a preference for smaller languages, I just haven’t seen anything in my career to indicate that smaller languages outperform when it comes to faster delivery or less bugs.
As an aside, I’d even go so far as to say that the main problem with C++ is not that it has so many features in number, but that its features interact with each other in unpredictable ways. Said another way, it’s not the number of nodes in the graph, but the number of edges and the manner of those edges.
Just an anecdote and not necessarily generalizable, but I can at least give one example:
I'm in academia doing ML research where, for all intents and purposes, we work exclusively in Python. We had a massive CSV dataset which required sorting, filtering, and other data transformations. Without getting into details, we had to rerun the entire process when new data came in roughly every week. Even using every trick to speed up the Python code, it took around 3 days.
I got so annoyed by it that I decided to rewrite it in a compiled language. Since it had been a few years since I've written any C/C++, which was only for a single class in undergrad and I remember very little of, I decided to give Go a try.
I was able to learn enough of the language and write up a simple program to do the data processing in less than a few hours, which reduced the time it took from 3+ days to less than 2 hours.
I unfortunately haven't had a chance or a need to write any more Go since then. I'm sure other compiled, GC languages (e.g., Nim) would've been just as productive or performant, but I know that C/C++ would've taken me much longer to figure out and would've been much harder to read/understand for the others that work with me who pretty much only know Python. I'm fairly certain that if any of them needed to add to the program, they'd be able to do so without wasting more than a day to do so.
2 replies →
> I’m not saying it’s wrong to have a preference for smaller languages, I just haven’t seen anything in my career to indicate that smaller languages outperform when it comes to faster delivery or less bugs.
I can imagine myself grappling with a language feature unobvious to me and eventually getting distracted. Sure, there is a lot of things unobvious to me but Go is not one of them and it influenced the whole environment.
Or, when choosing the right language feature, I could end up with weighing up excessively many choices and still failing to get it right, from the language correctness perspective (to make code scalable, look nice, uniform, play well with other features, etc).
An example not related to Go: bash and rc [1]. Understanding 16 pages of Duff’s rc manual was enough for me to start writing scripts faster than I did in bash. It did push me to ease my concerns about program correctness, though, which I welcomed. The whole process became more enjoyable without bashisms getting in the way.
Maybe it’s hard to measure the exact benefit but it should exist.
1: https://9p.io/sys/doc/rc.html
I think Go is a great language when hiring. If you're hiring for C++, you'll be wary of someone who only knows JavaScript as they have a steep learning curve ahead. But learning Go is very quick when you already know another programming language.
I agree that empirical data in programming is difficult, but i’ve used many of those languages personally, so I can say for myself at least that I’m far more productive in Go than any of those other languages.
> As an aside, I’d even go so far as to say that the main problem with C++ is not that it has so many features in number, but that its features interact with each other in unpredictable ways. Said another way, it’s not the number of nodes in the graph, but the number of edges and the manner of those edges.
I think those problems are related. The more features you have, the more difficult it becomes to avoid strange, surprising interactions. It’s like a pharmacist working with a patient who is taking a whole cocktail of prescriptions; it becomes a combinatorial problem to avoid harmful reactions.
I've been writing go professionally for about ten years, and with go I regularly find myself saying "this is pretty boring", followed by "but that's a good thing" because I'm pretty sure that I won't do anything in a go program that would cause the other team members much trouble if I were to get run over by a bus or die of boredom.
In contrast writing C++ feels like solving an endless series of puzzles, and there is a constant temptation to do Something Really Clever.
> I'm pretty sure that I won't do anything in a go program that would cause the other team members much trouble
Alas there are plenty of people who do[0] - for some reason Go takes architecture astronaut brain and wacks it up to 11 and god help you if you have one or more of those on your team.
[0] flashbacks to the interface calling an interface calling an interface calling an interface I dealt with last year - NONE OF WHICH WERE NEEDED because it was a bloody hardcoded value in the end.
Go is okay. I don't hate it but I certainly don't love it.
The packaging story is better than c++ or python but that's not saying much, the way it handles private repos is a colossal pain, and the fact that originally you had to have everything under one particular blessed directory and modules were an afterthought sure speaks volumes about the critical thinking (or lack thereof) that went into the design.
Also I miss being able to use exceptions.
8 replies →
The tradeoff with that language simplicity is that there's a whole lot of gotchas that come with Go. It makes things look simpler than they actually are.
I learned Go this year, and this assertion just... isn't true? There are a bunch of subtleties and footguns, especially with concurrency.
C++ is a basket case, it's not really a fair comparison.
> I'm convinced no more than a handful of humans understand all of C# or C++
How would the proportion of humans that understand all of Rust compare?
For Rust vs C++, I'd say it'll be much easier to have a complete understanding of Rust. C++ is an immensely complex language, with a lot of feature interactions.
C# is actually fairly complex. I'm not sure if it's quite at the same level as Rust, but I wouldn't say it's that far behind in difficulty for complete understanding.
I'm pretty convinced that nobody has a full picture of Rust in their head. There isn't even a spec to read.
1 reply →
Rust managed to learn a lot from C++ and other languages' mistakes.
So while it has quite a bit of essential complexity (inherent in the design space it operates: zero overhead low-level language with memory safety), I believe it fares overall better.
Like no matter the design, a language wouldn't need 10 different kinds of initializer syntaxes, yet C++ has at least that many.
Rust is very advanced, with things like higher-ranked trait bounds (https://doc.rust-lang.org/nomicon/hrtb.html) and generic associated types (https://www.ncameron.org/rfcs/1598) that are difficult because they are essential complexity not accidental complexity.
For Rust I'd expect the implementation to be the real beast, versus the language itself. But not sure how it compares to C++ implementation complexity.
Rust isn’t that complicated if you have some background in non GC languages.
2 replies →
This is also what I like about JS, except it's even easier than Go. Meanwhile Python has a surprising number of random features.
ECMAScript is an order of magnitude more complicated than Go by virtually every measure - length of language spec, ease of parsing, number of context-sensitive keywords and operators, etc.
4 replies →
Sorry, hard disagree. Try to understand what `this` means in JS in its entirety and you'll agree it's by no stretch of the imagination a simple language. It's more mind-bending and hence _The Good Parts_.
I think JS is notoriously complicated: the phrase “the good parts” has broad recognition among programmers.
Just so we're on the same page, this is the current JS spec:
https://262.ecma-international.org/16.0/index.html
I don't agree. (And frankly don't like using JS without at least TypeScript.)
2 replies →
https://jsdate.wtf/
The Javascript world hides its complexity outside the core language, though. JS itself isn't so weird (though as always see the "Wat?" video), but the incantations required to type and read the actual code are pretty wild.
By the time you understand all of typescript, your templating environment of choice, and especially the increasingly arcane build complexity of the npm world, you've put in hours comparable to what you'd have spent learning C# or Java for sure (probably more). Still easier than C++ or Rust though.
4 replies →
[flagged]
I’ve been using Python since 2008, and I don’t feel like I understand very much of it at all, but after just a couple of years of using Go in a hobby capacity I felt I knew it very well.
> Which makes sense, it's got the smallest language spec of any of them
I think go is fairly small, too, but “size of spec” is not always a good measure for that. Some specs are very tight, others fairly loose, and tightness makes specs larger (example: Swift’s language reference doesn’t even claim to define the full language. https://docs.swift.org/swift-book/documentation/the-swift-pr...: “The grammar described here is intended to help you understand the language in more detail, rather than to allow you to directly implement a parser or compiler.”)
(Also, browsing golang’s spec, I think I spotted an error in https://go.dev/ref/spec#Integer_literals. The grammar says:
Given that, how can 0600 and 0_600 be valid integer literals in the examples?)
You're looking at the wrong production. They are octal literals:
Thanks! Never considered that a 21st century language designed for “power of two bits per word” hardware would keep that feature from the 1970s, so I never looked at that production.
Are there other modern languages that still have that?
0600 and 0_600 are octal literals:
Never mind, I was wrong. Here’s a playground showing how go parses each one: https://go.dev/play/p/hyWPkL_9C5W
2 replies →
My original comment was incorrect. These are being parsed as octals, not decimals: https://go.dev/play/p/hyWPkL_9C5W
Well that's good, since Go was specifically designed for juniors.
From Rob Pike himself: "It must be familiar, roughly C-like. Programmers working at Google are early in their careers and are most familiar with procedural languages, particularly from the C family. The need to get programmers productive quickly in a new language means that the language cannot be too radical."
However, the main design goal was to reduce build times at Google. This is why unused dependencies are a compile time error.
https://go.dev/talks/2012/splash.article#TOC_6.
> This is why unused dependencies are a compile time error.
https://go.dev/doc/faq?utm_source=chatgpt.com#unused_variabl...
> There are two reasons for having no warnings. First, if it’s worth complaining about, it’s worth fixing in the code. (Conversely, if it’s not worth fixing, it’s not worth mentioning.) Second, having the compiler generate warnings encourages the implementation to warn about weak cases that can make compilation noisy, masking real errors that should be fixed.
I believe this was a mistake (one that sadly Zig also follows). In practice there are too many things that wouldn't make sense being compiler errors, so you need to run a linter. When you need to comment out or remove some code temporarily, it won't even build, and then you have to remove a chain of unused vars/imports until it let's you, it's just annoying.
Meanwhile, unlinted go programs are full of little bugs, e.g. unchecked errors or bugs in err-var misuse. If there only were warnings...
Yeah, but just going back to warnings would be a regression.
I believe the correct approach is to offer two build modes: release and debug.
Debug compiles super fast and allows unused variables etc, but the resulting binary runs super slowly, maybe with extra safety checks too, like the race detector.
Release is the default, is strict and runs fast.
That way you can mess about in development all you want, but need to clean up before releasing. It would also take the pressure off having release builds compile fast, allowing for more optimisation passes.
4 replies →
I feel like people always take the designed for juniors thing the wrong way by implying that beneficial (to general software engineering) features or ideas were left out as a trade off to make the language easier to learn at the cost of what the language could be to a senior. I don't think the go designers see these as opposing trade offs.
Whats good for the junior can be good for the senior. I think PL values have leaned a little too hard towards valuing complexity and abstract 'purity' while go was a break away from that that has proved successful but controversial.
> This is why unused dependencies are a compile time error.
I think my favourite bit of Go opinionatedness is the code formatting.
K&R or GTFO.
Oh you don't like your opening bracket on the same line? Tough shit, syntax error.
But it also has a advantages that you can literally read a lot of code from other devs without twisting your eyes sideways because everybody has their own style.
Doesn't Google use mostly C++?
Just because it was a design goal doesn't mean it succeeded ;)
From Russ Cox this time: "Q. What language do you think Go is trying to displace? ... One of the surprises for me has been the variety of languages that new Go programmers used to use. When we launched, we were trying to explain Go to C++ programmers, but many of the programmers Go has attracted have come from more dynamic languages like Python or Ruby."
https://research.swtch.com/gotour
2 replies →
It really depends on product area.
No.
Unfortunately, it's the remaining 20% of Rust features that provide 80% of its usefulness.
Funny thing is that also makes it easier on LLM / AI... Tried a project a while ago both creating the same thing in Rust and Go. Go's worked from the start, while Rust's version needed a lot of LLM interventions and fixes to get it to compile.
We shall not talk about compile time / resource usage differences ;)
I mean, Rust is nice, but compared to when i learned it like 10 years ago, it really looks a lot more these days, like it took too much of a que from C++.
While Go syntax is still the same as it was 10 years ago with barely anything new. What may anger people but even so...
The only thing i love to see is reduce executable sizes because pushing large executables on a dinky upload line, to remove testing is not fun.
I don't understand the framing you have here, of Rust being an asymptote of language capability. It isn't. It's its own set of tradeoffs. In 2025, it would not make much sense to write a browser in Go. But there are a lot of network services it doesn't really make sense to write in Rust: you give up a lot (colored functions, the borrow checker) to avoid GC and goroutines.
Rust is great. One of the stupidest things in modern programming practice is the slapfight between these two language communities.
Language can be bottleneck if there's something huge missing from it that you need, like how many of them didn't have first class support for cooperative multitasking, or maybe you need it to be compiled, or not compiled, or GC vs no GC. Go started out with solid greenthreading, while afaik no major lang/runtime had something comparable at the time (Java now does supposedly).
The thing people tend to overvalue is the little syntax differences, like how Scala wanted to be a nicer Java, or even ObjC vs Swift before the latter got async/await.
I'll be the one to nickpick, but Scala never intended to be a nicer Java. It was and still is an academic exercise in compiler and language theory. Also, judging by Kotlin's decent strides, "little Syntex differences" get you a long way on a competent VM/Runtime/stdlib.
Kotlin's important feature is the cooperative multitasking. Java code has been mangled all these years to work around not having that. I don't think many would justify the switch to Kotlin otherwise.
Go is getting more complex over time though. E.g. generics.
It really is a lovely language and ecosystem of tools, I think it does show its limitations fairly quickly when you want to build something a bit complex though. Really wish they would have added sumtypes
>> I'm sure there are plenty of reasons this is wrong, but it feels like Go gets me 80% of the way to Rust with 20% of the effort.
By 20% of the effort, do you mean learning curve or productivity?
I write a lot of Go, a bit of Rust, and Zig is slowly creeping in.
To add to the above comment, a lot of what Go does encourages readability... Yes it feels pedantic at moments (error handling), but those cultural, and stylistic elements that seem painful to write make reading better.
Portable binaries are a blessing, fast compile times, and the choices made around 3rd party libraries and vendoring are all just icing on the cake.
That 80 percent feeling is more than just the language, as written, its all the things that come along with it...
Error handling is objectively terrible in Go and the explicitness of the always repeating pattern just makes humans pay less attention to potentially problematic lines and otherwise increases the noise to signal ratio.
Error handling isn't even a pain to write any more with AI autocomplete which gets it right 95%+ of the time in my experience.
You're not wrong but... there is a large contingent of the Go community that has a rather strong reaction to AI/ML/LLM generated code at any level.
I keep using the analogy, that the tools are just nail guns for office workers but some people remain sticks in the mud.
5 replies →
Similar story for me. I was looking for a language that just got out of the way. That didn’t require me to learn a full imparable DSL just to add a few dependencies and which could easily produce some artifact that I could share around without needing to make sure the target machine had all the right dependencies installed.
> I'm sure there are plenty of reasons this is wrong, but it feels like Go gets me 80% of the way to Rust with 20% of the effort.
I don't see it. Can you say what 80% you feel like you're getting?
The type system doesn't feel anything alike, I guess the syntax is alike in the sense that Go is a semi-colon language and Rust though actually basically an ML deliberately dresses as a semi-colon language but otherwise not really. They're both relatively modern, so you get decent tooling out of the box.
But this feels a bit like if somebody told me that this new pizza restaurant does a cheese pizza that's 80% similar to the Duck Ho Fun from that little place near the extremely tacky student bar. Duck Ho Fun doesn't have nothing in common with cheese pizza, they're both best (in my opinion) if cooked very quickly with high heat - but there's not a lot of commonality.
> I don't see it. Can you say what 80% you feel like you're getting?
I read it as “80% of the way to Rust levels of reliability and performance.” That doesn’t mean that the type system or syntax is at all similar, but that you get some of the same benefits.
I might say that, “C gets you 80% of the way to assembly with 20% of the effort.” From context, you could make a reasonable guess that I’m talking about performance.
Yes, for me I've always pushed the limits of what kinds of memory and cpu usage I can get out of languages. NLP, text conversion, video encoding, image rendering, etc...
Rust beats Go in performance.. but nothing like how far behind Java, C#, or scripting languages (python, ruby, typescript, etc..) are from all the work I've done with them. I get most of the performance of Rust with very little effort a fully contained stdlib/test suite/package manger/formatter/etc.. with Go.
11 replies →
I guess the 80% would be a reasonably performant compiled binary with easily managed dependencies? And the extra 20% would be the additional performance and peace of mind provided by the strictness of the Rust compiler.
Single binary deployment was a big deal when Go was young; that might be worth a few percent. Also: automatically avoiding entire categories of potential vulnerabilities due to language-level design choices and features. Not compile times though ;)
Wild guess but, with the current JS/python dominance, maybe it’s just the benefits of a (modern) compiled language.