top | item 37107052

Rust vs. Go in 2023

90 points| saikatsg | 2 years ago |bitfieldconsulting.com | reply

204 comments

order
[+] satvikpendem|2 years ago|reply
Whenever I see comparisons between Rust and Go, I'm always reminded of fasterthanlime's I want off Mr Golang's wild ride [0] as well as its sequel Lies we tell ourselves to keep using Golang [1].

Having used both, Go hides its complexity behind the veneer of simplicity while being more tedious and error prone as the codebase grows while Rust brings the complexity to you upfront while preventing errors later. Personally, even simply due to language features like algebraic data types in other languages, I really have no reason to use Go anymore. There's an oft-said quip that says that the Go language designers took the last 50 years of programming language theory and simply...threw it away.

Plus, to those saying it's easier to hack stuff together in other languages than Rust, I simply clone everywhere and Rust then becomes the same as a garbage collected language. You don't have to deal with lifetimes and excessive cloning from the get go, deal with that after experimenting then optimize, same as you would for any other language. The plethora of language features in Rust make it easier to hack around in, in actuality.

[0] https://fasterthanli.me/articles/i-want-off-mr-golangs-wild-...

[1] https://fasterthanli.me/articles/lies-we-tell-ourselves-to-k...

[+] anyfactor|2 years ago|reply
I don't get paid to write code in these languages; my enthusiasm in exploring them is limited by the amount of energy I have over the weekend. Honestly, I don't see Rust as anything but a code-rewrite language.

I find Rust to be unintuitive, and I don't think it is a language designed to be a "problem solver.

So, what do I mean by a problem solver? If you have a problem and you write code by exploring different solutions, continuously improve, and write hacky stuff where the goal is to simply solve a problem.

Rust is not a problem solver; it is going to fight you all the way through because of its emphasis on programmatic correctness. With Rust, you have to have the solution first, consider the language-specific caveats, and write something in such a way that you don't go back and have to improve it. I suppose that is how programming is supposed to be done - in a clear and structured manner. But let's admit it, nobody does that.

On the other hand, Go is a language that sits between Python and Rust. Python is THE problem solver language, and Rust is an elegant and good etiquette language. Go just works as a hackable language with the benefits of a compiled language and type support.

My plan with Rust vs Go for the time being:

- If I need to solve a problem and can do continuous improvement on the codebase → Go - If I have the problem solved, I have the resources to do a rewrite → Rust

[+] dannersy|2 years ago|reply
Like someone else has said, I hear and understand what you're saying but I could not disagree more.

I write Rust professionally and what you hate about Rust is opposite to why I love it so much. Especially in larger projects, I have never in all my career had an easier time hacking and iterating. I'm infinitely more confident in writing a ton of lines that will work once I compile. In Python and Go, I could end up chasing silly bugs and waste time debugging and tracing to find that I made a typo or ran into a language quirk that gave me an unexpected nil pointer. That situation is almost non-existent in Rust, it's just me and the problem. Rust is honest and upfront about its quirks and will yell at you about it before you have a hard to find bug in production.

Those last two sentences aren't 100% true. Advanced Rust can be tough and you absolutely will fight with it. But to be perfectly honest, this gets rare over time and usually it comes from a lack of understanding. When you finally do understand, it's another tool to add to your belt that makes you a better programmer.

[+] satvikpendem|2 years ago|reply
Not really. I use unwrap and clone everywhere and I can do everything as if Rust were then a garbage collected language, and I can then test out different solutions, hack my way through, just as I would in Go or Python. Then once I have a good solution, even if I don't optimize it, it is leagues faster than Python and even faster than Go. If I do decide to optimize it, then, it's fast, really fast.

IMO those who say Rust isn't suitable for hacking seem to try to conform to best practices right away when really, dealing with lifetimes and excessive clones should be part of the optimization step, not the ideation and experimentation steps. Rust is as high level as you want it to be. Hell, I write web backends and sometimes even frontends in just Rust and I never worry about memory until I want to optimize, if I even want to optimize.

[+] deaddodo|2 years ago|reply
While I hear you and grok+understand you; I think this 100% comes from your background and what problems you are trying to solve. As someone that does a ton of systems (traditional definition; e.g. embedded, OS, emudev, etc) development in my hobby time, Rust (and Zig, more often these days [for me]) is perfectly conducive to my use cases and improves my development flow; while using Go would get in the way far too often.

But when I do work Go excels in (web architecture, especially), I'm not particularly keen on using Rust or Zig in it's place. While it's perfectly possible to build a Postgres-fronting, redis-cached microservice to manage users, auth, etc in Rust, it's going to be an exercise in frustration compared to something more streamlined for that task.

[+] peterfirefly|2 years ago|reply
My first (and so far only) Rust program was an 8088 disassembler. Rust made it easy for me to try "different solutions, continuously improve, and write hacky stuff".

Perhaps it's more a question of background? Rust contains many features I already know from the ML family + it formalizes the way I've already been thinking about memory since the early 90's.

[+] thumbuddy|2 years ago|reply
If you spent more time with rust your opinion of it would change. It's strength has nothing to do with rewriting software. It's easy to maintain, and pretty fast to write.

I prefer go for cloud integrations because they tend to have the best implementations and most solid APIs. That's about it though.

Python is a good bash replacement, but I don't like writing large projects in it. It's hard to maintain and the errors that come from production are never straightforward. Good for some medium scale mathy compute projects though.

C++ is where I write most math code after prototyping it elsewhere(R or Python)

Rust for me is the answer to most things except, it's ecosystem is a bit weak, and it's a bit of a clout chaser language(not as bad as others though)

[+] bibabaloo|2 years ago|reply
I think it's one of those things where you need to drink the coolaid. Once you get over the learning hump and fighting against you, you won't want to go back to languages with poorer and less strict type systems. There a lot of value in letting the compiler do it for you
[+] littlestymaar|2 years ago|reply
> With Rust, you have to have the solution first, consider the language-specific caveats, and write something in such a way that you don't go back and have to improve it. I suppose that is how programming is supposed to be done - in a clear and structured manner. But let's admit it, nobody does that.

And that's absolutely not how you do it in Rust either. Once you've internalized the Rules of the language, you can definitely grok your solution in Rust the same way you'd do in Python, the biggest difference being that Rust will help you a lot more when refactoring your code to the next iteration, so you'd be more efficient over a few days of work in Rust than in Python.

The big caveat being that you need to actually learn the language first instead of pretending you're a polyglot developer and you can write code in any language without having to spend time learning it, but maybe you'd argue that nobody does that either…

[+] IshKebab|2 years ago|reply
> You may have read articles and blog posts aiming to convince you that Go is better than Rust, or vice versa. But that really makes no sense; every programming language represents a set of trade-offs. Each language is optimised for different things, so your choice of language should be determined by what suits you and the problems you want to solve with it.

That's sort of true, but I wish people would stop cowardly saying that you can't say that one language is better than another overall. That's clearly not true.

IMO this article is very very long and doesn't really highlight the differences well, which IMO are:

* Go has much faster compile times.

* Rust's tooling is very good but I would still say Go's is better. It has built in fuzzing support! Cross compilation is as simple as setting an environment variable.

* Rust is a little faster, and avoids GC.

* Go's standard library is much more comprehensive than Rust's.

* Go is much easier to learn and to read.

* Rust is a better language if you have learnt it. It has much more powerful features (especially the functional ones) and is more principled. Going back to Go from Rust is frustrating.

* Rust has a much stronger type system and the borrow checker. Both make bugs far less likely.

* Async Rust is probably the worst bit about Rust. Go's goroutines are much easier to use. Though I would say traditional multithreaded code in Rust is pretty easy - it's just that a lot of the ecosystem forces you into async.

[+] LambdaComplex|2 years ago|reply
Yeah, I really felt like this article had a lot of words and yet didn't actually convey much useful information—nor did it convey any information that hasn't been written about at length elsewhere.

I also found this sentence to be confusing:

> If you only have time to invest in learning one language well, don’t make your final decision until you’ve used both Go and Rust for a variety of different kinds of programs, large and small.

So, if I only have the time to learn one language, I should...use two languages? For multiple projects? But somehow without learning them, because I don't have time?

[+] threeseed|2 years ago|reply
> Rust is a little faster, and avoids GC

Depending on what you're doing.

I am finding that Rust is easily beating all of the non-C languages in terms of full support for the latest performance technologies e.g. io_uring, SIMD (AVX2/AVX512/NEON), DirectStorage, CUDA etc as well as the highest quality wrappers for C/C++ libraries.

So for many applications Rust will simply leave Go for dust.

In fact for me the only benefits of Go are single binary and startup time. Otherwise I find Rust to be ideal for when I need low level performance. And Scala to be significantly better for backend apps since its faster, has access to more libraries, better concurrency and a stronger type system resulting in much more reliable code.

[+] luuio|2 years ago|reply
At least two reasons I'm not choosing Go:

- Go (the language) is missing the ability to declare something immutable. I don't mean making fields in a struct private then exposing getters. I mean the equivalent of an immutable reference in Rust or `const ref` in C++.

- Go mod and go workspace still can't get a cohesive story together [1]: - - If my module wants to depend on another module in a workspace, `go mod tidy` would freak out. - - If I use replace in my go mod file to point to the other modules in the same workspace, `go mod vendor` will copy these workspace modules to the vendor folder as well.

[1] https://github.com/golang/go/issues/50750

[+] diarrhea|2 years ago|reply
> * Rust is a little faster, and avoids GC.

I always wondered: how is it not much faster? Dealing with the borrow checker is immense overhead, yet performance gains are low compared to Go. Is Go's GC simply that good? Is Rust's compile-time GC about something other than performance somehow?

I realize Go still needs to ship a minimal runtime in its binaries, but don't feel that's a meaningful burden compared to borrow checker fighting.

[+] atmosx|2 years ago|reply
> Go's goroutines are much easier to use.

True. Golang multithreading is easy to reason to about. I had to make some mental gymnastics to write multithreaded scripts in Ruby and Python. The Golang implementation was the easiest by far.

[+] k_bx|2 years ago|reply
Rust is your "last language". It's good for writing Python native modules, PostgreSQL native modules, compiling to WASM, all using the same libraries you love and know already. That is a big deal for me.
[+] rapsey|2 years ago|reply
If you are interfacing with other languages or running on mobile (as a library not a full app) Rust is the obvious right choice imo. In other situations the choice is not as clear cut.
[+] brabel|2 years ago|reply
> Rust has a much stronger type system and the borrow checker. Both make bugs far less likely.

I really prefer strong type systems over weak ones, but despite that, I always like to point out that there's no evidence that strong type systems cause "bugs to be far less likely". No study I've seen (quite a few) has ever shown that.

There's a few bugs that become impossible (in Rust, some kinds of data races for example) but the vast majority of bugs can still occur and in practice, do occur.

[+] colonwqbang|2 years ago|reply
Interesting that he selected "match" as example of a complex Rust feature. To me, "match"/"case" is one of the simplest and cleanest abstractions in programming languages.
[+] Havoc|2 years ago|reply
I was agonizing over this choice too. Eventually rust won:

* Feels closer to the good old Pascal days where you control everything

* Safer bet should wasm & friends explode

* Already have python for quick & dirt so picking something more extreme made sense. Go feels sorta in the middle

* Its in kernel & loads of hype so unlikely to go away

[+] zozbot234|2 years ago|reply
Go is only memory safe for simple sequential code. Most concurrent Go programs share memory among threads/goroutines in an unsafe way.
[+] jedisct1|2 years ago|reply
On the other hand, goroutines makes it very easy to write concurrent code. And the built-in checker for race conditions works well.

Async Rust, OTOH, can quickly become a horrible spaghetti mess that's virtually impossible to debug, and where common things such as cancellation are very challenging.

My networks servers written in Rust are unsafe.

I know they have dead locks, memory safety issues (due to usage or shared arrays and slabs to avoid allocations and work around the borrow checker), can be remotely DOS'd, leak memory (due to Rc, cycles or whatever), and have hacks to work around APIs that are not easy to use, just to make the borrow checker happy. Doing simple things such as listening to multiple IP addresses can require a major refactor.

At the end of the day, after the excitement of having written a first version of these projects, I have a hard time understanding and fixing the remaining bugs, and eventually stop maintaining them.

The ecosystem is also unstable. Dealing with major changes, or crates that need to be replaced because of deprecation/abandon makes applications unsafe. "crap, after cargo upgrade, that doesn't compile any more. Let's randomly fiddle around so that it compiles again". The version with the new crates doesn't get tested as much as the previous one. If they behave differently, or if to get the behavior of function X, now one should call function Y because X now does something else, the application is not as safe as when originally written.

My network servers written in Go probably have plenty of bugs, but I can understand what's going on and fix them. I can dive into the code of the dependencies and of the standard library, follow and understand how things work under the hood. With Go's rich standard library, I also don't need to rely on a ton of dependencies, that will constantly be abandoned or introduce breaking API changes.

So I can stay focused on the application logic, and eventually, the Go servers are way safer from a practical perspective. And for something that must be maintained on the long term, Go also wins hands down.

[+] kaba0|2 years ago|reply
That causes concurrency issues, but that is not what is commonly understood by memory safety.

With that said, Go indeed gives you plenty of rope to hang yourself with in relation to concurrency (among others).

[+] benrutter|2 years ago|reply
I think this article is a nice summary of the languages, but the opening set up bugs me:

> Which is better, Rust or Go? Go or Rust? Which language should you choose for your next project in 2023, and why?

I blame the "rewrite everything in Rust" crowd, but there seems to be a resurgence lately of the idea that there is One True Programming Language you should use for everything.

I don't particularly fancy using an OS written in Go, and I don't want to work on web architecture projects in Rust. Similarly, I don't want to work with someone who is going to write shell scripts or basic utility tasks in Rust because the performance is faster.

[+] ssokolow|2 years ago|reply
Odd. I wish Rust had Django's ecosystem so I could do more Rust web stuff, and I do use Rust for "shell scripts" and basic utility tasks, not for the performance, but for the compile-time guarantees.

I'd much rather pay a little extra up-front in resolving compiler errors, so I can know I'm not going to wake up to something like a six-hour batch job that failed 5% through or slam face-first into needing to debug an exception when I'm already in a rush and stressed over it.

Likewise, I find Rust's syntax much more pleasant than Go's... probably because I can see that Rust's syntactic complexity means things that have value to me, while Go's is just repetitive boilerplate to make my time a sacrifice on the altar of dogmatic language simplicity.

[+] luuio|2 years ago|reply
At least two reasons I'm not choosing Go:

- Go (the language) is missing the ability to declare something immutable. I don't mean making fields in a struct private then exposing getters. I mean the equivalent of an immutable reference in Rust or `const ref` in C++.

- Go mod and go workspace still can't get a cohesive story together [1]: - - If my module wants to depend on another module in a workspace, `go mod tidy` would freak out. - - If I use replace in my go mod file to point to the other modules in the same workspace, `go mod vendor` will copy these workspace modules to the vendor folder as well.

[1] https://github.com/golang/go/issues/50750

[+] truth_seeker|2 years ago|reply
The difference/tradeoff shown in the blog fades away in developers psychology as they write more code and ship apps, so I would not held them high.

In my experience, compared to Golang, the only (mild) downside of Rust is not so big STD lib, compilation time and initial learning curve. Frankly speaking its neither a blocker nor a big deal. Once learning phase of Rust is passed, you have one language which you can use anywhere and can trust to produce efficient code both from readability and performance point of view.

[+] zarzavat|2 years ago|reply
Rust vs Go is like Jeep vs Prius. They both do the same kind of thing, but in such contrary ways that I don’t think anyone is confused which one they want.
[+] msie|2 years ago|reply
After reading many comments here the one that appeals to me is the readability of go code. There was this moment of ruby vs python where I was delighted by the readability of python code and how I could easily read the code of python libs as well. I feel this is the same with go. I can imagine the rust wizards easily making hard to read code.
[+] bamazizi|2 years ago|reply
I've tried Rust for a short while to get a good feel. I've been Go developer for nearly a decade. Unfortunately there's a bit of a forced and misleading Rust favoritism the days but from my experience in various startups, including my current one, Go is by far the best choice for backend development!

- Rust is not suitable for fast paste startup environment

- Rust is not suitable if the initial team members are not Rust experts

- Rust is not suitable if the startup doesn't have money (Rust devs are very expensive and scarce)

- Rust is not general hire friendly

- Rust is not ideal for iterative and high refactor potential of startup culture

- Rust is painful/heartbreaking when eventuality of a pivot approaches

- Rust is not an advantage in anything startup related

Go is the exact opposite of above points! Note: I didn't talk about performance, feature or whatever else ... both languages are very very close to each other!

[+] xyproto|2 years ago|reply
Pretty balanced article, but I think it skips over the (for me) main points of using Go:

* Go was developed within Google, mainly as a response to C++ projects that had grown unwieldy, in terms of dependencies and compilation speed. As a result, the language is designed from scratch with compilation speed in mind, and unused dependencies are disallowed.

* There are few changes to the language. When a new Go compiler is released, I go "nice, wonder which tooling and performance improvements are present" and not "oh no, how many repositories will need patches". Go code can be expected to compile 10+ years ahead. The same is not always the case for C, C++, Zig and possibly even Rust.

* Deployment and crosscompilation is straightforward.

[+] deaddodo|2 years ago|reply
> Go code can be expected to compile 10+ years ahead. The same is not always the case for C, C++, Zig and possibly even Rust.

I'm sorry, but this comment just seems so blind to reality that it's hard not to comment on. C has a few particularly strong selling points:

* Orthogonality to machine architectures

* Freestanding (STD-free, in modern language parlance) compilation

* An extremely conservative ruling body

The latter is usually listed as a double-edged sword, since there are many new features people would like in C: true generics, polymorphic (overloaded) functions (without using the pre-processor), a true module system, etc; but it also means extremely old code compiles just fine on modern C compilers. Now, it might not work because it might be built for some bespoke hardware/environment, but the code will compile fine and be correct.

For instance, here's a perfectly valid ANSI C application that will compile on any C compiler in the last 35 years (three times as long as Go has existed):

https://godbolt.org/z/ja6WM5feT

Most of the features added in C11, C17 and C23 are additional features, usually with no backwards breaking changes. However, in some cases they do clarify undefined behavior; which can break old code. This is why most of the major modern compilers add flags to compile in specific dialects.

Additionally, there are plenty of Go 1.0 (the first [and only] "10+" [11] year old version) codebases that won't compile without major changes.

[+] orwin|2 years ago|reply
Just compiled my 10 year old C project to test this claim. No issues (and it was written in C89, not C99 nor C11).

And couldn't compile my 9 year old Go project (a small supervisord clone) a few month ago (it was either in go 1. 2 or 1.3). Granted, it was a library issue (terminfo/ncurse, I can't remember which), but still.

I'm not a huge C proponent anymore (except as a learning language), but C is absolutely more stable than most languages, especially if you account for external libs.

[+] usrnm|2 years ago|reply
> The same is not always the case for C, C++

That's just completely not true, especially for C. There is a lot of C code older than most commenters on this site that's still used in production and compiled with modern compilers

[+] bestouff|2 years ago|reply
> and possibly even Rust.

This is patently false. Rust has a severe backwards compatibility policy.

[+] kif|2 years ago|reply
What is the recommended resource that helps one become proficient at Rust nowadays?
[+] peterfirefly|2 years ago|reply
[+] thumbuddy|2 years ago|reply
Just practice. Screw all the "how to learn x" grind culture stuff. Just download it. Build a project with it. Read other people's code. Rinse and repeat.
[+] speedgoose|2 years ago|reply
I would recommend ChatGPT. It’s pretty good at pretending to understand your struggles with rust. You can explain your issues and swear a lot and you will get a nice explanation in return.
[+] pjmlp|2 years ago|reply
Most of my complaints against Go are kind of waned, however can we at very least have Pascal like enumerations without iota const dance?
[+] leighmcculloch|2 years ago|reply
The article doesn't discuss one of the most significant differences between building in Go and Rust: tooling.
[+] kaba0|2 years ago|reply
Rust and Go have almost no relation to each other - one is a low-level language, like C, C++, the other is a high-level one like Java, C#, Haskell.

These articles and this general notion that the two has some relevance to each other is just plain wrong and harmful.

[+] impulser_|2 years ago|reply
There are definitely relations between them. They are often used in the same domains. Servers, DevOps, CLI, tooling ect. Just because one has manual memory management and other is GC doesn't mean they aren't relatable.
[+] leftyspook|2 years ago|reply
Rust is a low-level language with high level abstractions, while Go is a high level language with low level abstractions.
[+] valenterry|2 years ago|reply
> Java, C#, Haskell

Mentioning Haskell within the same enumeration that contains Java and C#. Blasphemy!

[+] ducktective|2 years ago|reply
>Which is better, Rust or Go? Go or Rust? Which language should you choose for your next project in 2023, and why?

Meanwhile, I'm here considering Common Lisp :)

Not being able to generate a statically compiled binary is an issue though...

[+] gerardpg|2 years ago|reply
Go needs more syntactic sugar.
[+] barnabee|2 years ago|reply
I honestly think the only remaining thing I'd need from Go to almost never pick up Rust for a new project is sum types.

If there was a NewGo with no concept of a raw 'nil' value (replaced by Maybe<T>) and err, res in the standard library replaced with Result<T, E>, I'd have vanishingly few reasons to use Rust.

If we got TinyNewGo too for embedded/WASM… uh oh