Soft question, golang vs Rust, productivity

Hmm... Despite having used C++ for a long time I have studiously avoided ever having anything to do with template meta programming. When things get too meta, I hit my abstraction ceiling. That and the ugly syntax crashes my visual cortex or something.

I suspect the same will happen with Rust macros. Something I keep meaning to get around to studying properly....

2 Likes

I feel like the philosophies of the two languages are so opposite that I don't know how often people willingly dual-wield them. At least, I've never met anyone who was a big fan of both -- they seem to either much prefer Go's style of simplicity, or much prefer Rust's style of precision.

I'm not sure that's really the language's fault. In a prototype, one should be reaching for "well I'll just clone it", not "how can I refactor things to allow borrowing here" (unless lifetimes are the core of what you're prototyping).

5 Likes

I have used both Go and Rust in 5-10 small projects that have real world use for me.

Rust certainly feels like it takes more of your energy in the startup phase:

  • What data flow do I want?
  • Stack or heap?
  • Lifetime struggles
  • etc.

But in the long run I do feel like Rust has served me better.

The thing about Go is that it seems simple on the surface but has some really irritating things that really grind my gears:

  • I hate writing if err != nil on every fifth row.
  • Go interface instances can contain nil values that crash your program so you have to check if the thing you are nil checking is an interface first and then check if the internal value is nil. Wow.
  • Goroutines are not thread safe if you share pointers through a channel.

You can definitely get great mileage out of Go, but there are a lot of GOtchas that you need to always be weary of.

I do think that the Rust proponents saying "if it compiles it runs" aren't right, at least as far as "runs" means bug free which it obviously is not.

But obviously you're asking on a Rust forum so obviously people here probably like Rust better :slight_smile:

12 Likes

Valid point. I do not know of many (any) either. Part of what motivated this question is that I was skimming source code for novel database / distributed systems -- expected to see most of it in Rust/C++, but was surprised to see GoLang all over the place.

1 Like

waves :slight_smile:

I have a lot of complaints about Go that I've talked about before on this forum. I have fewer complaints about Rust. But I still like Go a lot, and in particular, its "simplicity" (for my definition of "simplicity") appeals to my sensibilities personally.

10 Likes

@BurntSushi I really like this quote from What made you choose Rust over Go? - #7 by BurntSushi

I actually try hard to blend some of those goals that I find appealing into Rust code that I write. It can be very difficult at times. In general, I do my best to avoid writing generic code unless it's well motivated, or manifests in a way that represents a common pattern among all Rust code. My personal belief is that Go's lack of generics lends considerably to its simplicity. Writing in Go code heavily biases towards less generic code, and thus, more purpose driven code and less YAGNI code. I don't mean this to be a flippant comment; the best of us succumb to writing YAGNI code.

It expresses much more clearly what I was trying to state.

3 Likes

I guess it happens but I don't recall any Rust proponent claiming that if ones Rust code compiles then it is bug free. Obviously not true as you say.

What I do see often are statements to the effect that if ones Rust code compiles it is more likely to be correct. Which I feel is true. Not "correct" but "more likely".

The important point for me though is that when ones Rust code does have bugs they seem to be a lot easier to find.

In many languages there is no chain of cause and effect discernible by inspecting the source code. A bug in function A can show up in the behaviour of function B. Ones bugs can misuse memory causing random data corruption, race conditions and mysterious crashes. Those symptoms may show up in parts of your code unrelated to the location of the actual bug, they may show up a long time after the actual bug did it's dirty work.

Which I suspect is why debuggers are popular tools in those worlds.

On the the other hand Rust does not allow such memory misuse bugs to hide unnoticed. They cannot cause other unrelated parts of ones code to fail. There is a chain of cause and effect discernible in the source code.

4 Likes

I love it. I thought I was only me that shied away from such generalisation, generics, encapsulation and thoughts of reuse. Typically I have the feeling it would take me lot longer to figure out how to generalise something than to cut, paste and tweak it as needed. And the resulting code, now weighed down with the syntax and semantics of generics, templates, whatever, would be a lot harder for anyone to read.

Never heard "YAGANI" before. Apparently its a thing in the Extreme Programming world. Itself something I know nothing about.

I am not alone. I feel much better about myself now. Thanks.

3 Likes

It happens to me in Python too.

Thank you for an honest question and not starting a flame war. For some context, I have been programming for about 4 years, starting with Python, then Javascript, then adding Go and Rust. Here are some thoughts from my end, which probably fall somewhat short of an actual answer. As a full disclosure, I am sympathetic toward Rust and not entirely unbiased.

I suspect I am not the only person here who has lost a weekend in advanced-trait / procedural-macro black magic, only to wonder "wtf was the original problem I was working on again?"

You are in good company my friend. Rust's breadth and depth is a two-edged sword. Sometimes people say Go and Rust are similar in that they both get used for modern microservices (which is true), but Go is fanatical about simplicity and Rust is fanatical about correctness from first principles, which are very different approaches.

Many developers have claimed Go is one of the quickest languages to start being productive in. I suspect they are right. Go has the dead-simple "net/http" package as the de-facto way of creating an http server. Rust takes a package AND more boilerplate to get there. Which one do you use? Actix? Rocket? Hyper? All of the sudden I feel like I need to investigate three potential ways of doing a thing, whereas Go only ever gave me one option.

But that is at the beginning of the project. Toward the end, after you have written several thousand lines of code and start to forget the breadcrumbs you dropped along the way, is where I feel like Rust is in its element. There is no such thing as a nil/Null value that can creep up. All the dependencies seven layers down that could throw an error have to be dealt with explicitly with a Result<>. People sometimes describe the unique feature of Rust as being "fearless concurrency", but I think that is a rather niche concern. I want my code to handle all the "what ifs" I'm not smart enough to keep track of in my head. I am currently re-writing an application that was about 7,000 lines of python in Rust. Things are damn slow to start when you have to select which approach to take, but once you make those choices, the compiler is a rock that pulls you downhill toward completion, not a rock you have to push uphill.

Long way of saying I think the path to productivity likely is faster with Go for the first few hundred lines of code. The things where rust particularly shines (in my opinion) don't really show their full value until your codebase gets larger.

13 Likes

I spent five years writing mainly in Go, then in the last few months have started writing in Rust. In both cases, the language choice was made by the company I work/ed for, not me, so it's not a question of personal preference. I also have Node.js/Typescript and C# to compare to. Because my Rust proficiency is between beginner and intermediate (I haven't, for instance, written any serious macros yet), I cannot really legitimately compare productivity yet, but I do have some subjective impressions. I try not fall into fanboyism for any language or framework, so I hope this is a reasonably fair-minded and unbiased perspective.

I can believe that with time, I may be able to approximate my Go-level productivity using Rust, but that is still a long way off. A few factors contribute to this. Firstly, the in-editor experience has not been great for me with Rust. Partly because macros make it much harder for the language server to do things like "go to definition". Also because, for example, a single C library dependency that I can't compile on my Mac means I have no intellisense at all for the project. That would not happen in Go. Secondly, borrow-checking and lifetime checking are painful for a programmer newish to the language because they represent a new class of compile-time errors - not syntax errors or type errors, which will be pointed out immediately in your editor, but usage errors that relate to how and where variables are used in relation to one another and which only get detected when you do cargo build. Thirdly, the zero-cost abstractions do have a cost, just paid by the programmer rather than the computer. The async abstractions in particular are awkward to use. Try joining futures with return types that look the same but actually have different underlying concrete types, for example. Oh, says my Rust mentor, you need to whack a .boxed_local() on the end of that... Say what?

Productivity in Go is hampered by all those horrible if err!=nil clauses and lack of generics causing you to use a code generator or simply cut and paste functions... but hell, they got concurrency right!

Anyway, I understand how the philosophical starting point of Rust leads to all this, and it's fine. It's a fantastic language in many ways, and I'd choose it over Go for anything high performance or with low-level C interop requirements. But there's no denying these things have and do affect my productivity using it. Compare it with Node + Typescript and the productivity gap is even larger. That said, it also true that the Rust code I write does seem to have fewer bugs than other languages - the no data race guarantee is particularly nice; I've wasted weeks chasing data races in Go.

There's evidence for the case that getting a major project up in Rust is slower than other languages, at least if the developers are having to learn the language - I remember reading about parallel teams developing the same project in Rust, Go and a number of other languages, and the Rust project (all developers were starting as language beginners) was much slower than the others. I wish I could find the reference...

Like I say, none of this is to knock Rust. I'm really looking forward to the day when I can churn out Rust code the way I can churn out Go, because it will be tighter, faster code. But there's no denying the productivity cost of getting there.

11 Likes

Thank you for sharing your experiences.

Are you using IntelliJ? With the latest, I have macros that define new structs and, on 'goto def', IntelliJ, somehow, can jump me to the line where the macro is called (to define the new structs).

Ah, this reminds me. There are certain things in pattern matching easier to do in OCaml/Haskell than Rust, and there are certain things in dealing with anonymous functions easier to do in OCaml/Haskell/Lisp, but where Rust's zero cost abstractions increases programmer work.

I have been using exclusively Go at work from the last 3.5 months but Rust is my favorite general purpose language for my personal projects.

In general I like them both, but I think the philosophies behind the languages are very different. In terms of productivity some of the things I think Go is better at are:

  • Simplicity: I work on a large code base with >50 developers and having a simple language where there is really only one idiomatic way to write the code ensures that there is a general consistency across the board in the way the code is written. Inexperienced developers and people new to Go pick it up quickly and the amount of time until they can actually start contributing in meaningful ways is a lot shorter than Rust.
  • IDE support: Go is better than Rust. I use VS Code for both and while I constantly encounter bugs in rust-analyzer, but I rarely have an issue with Go. I think the gap is closing fast here though!
  • Go interfaces are really intuitive and an easy to use abstraction, and less verbose than Rust traits.
  • Writing goroutines is much easier than writing async Rust.

The following things I think affect productivity in Go:

  • Panics because of nil pointer dereferencing: these are very annoying to debug in production.
  • Lack of compiler output: the Rust compiler really has some of the best compiler output and the Go compiler seems to give as little as possible.
  • External tools to do codegen, in Rust you would just write a macro / proc macro.
3 Likes

I once heard a wise man say "stress is two competing thoughts trying to occupy the same spot in your head". I've always tried to not get dragged down into quarrels over my favorite OS, language, framework etc. But I have felt stressed about choosing Go vs Rust for projects where I am the lead and if things break, everybody knows who to blame. Perhaps that is where some of the angst comes from in online chatrooms. In a way, things would be simpler in cases like yours where you are obligated to use a given language. If you job is to write it in Go, you write Go code. If your job is to write it in Rust, you write Rust. The fact that the tension can even exist means you can get there with either language.

2 Likes

This is a little bit off topic, but why is it that Go is always the language that people compare Rust to? As far as I can tell, they made tons of fundamentally opposite design decisions, so it seems to me that they would be about as comparable as Python and C, or Haskell and JavaScript. What is so similar about them that makes them worth comparing?

1 Like

IMHO: Python/Haskell/JS is a lot more high level than Go. It is not easy to define a Struct, then have an array of it where it is guaranteed that the in memory representation if a continuous block of memory.

1 Like

Is it possible to have such an array in Go? I thought that garbage collected languages needed to use indirection for all of their objects to do the reference counting thing, so you would have an array of pointers to objects instead of inlining them like rust. Either way, my point was that the languages seem different enough that they would be used to solve different classes of problems, so I'm confused why they are so frequently compared.

https://research.swtch.com/godata

One difference is that GoLang / Rust / C / C++ is often used at the "lowest level" of writing databases / key value stores / distributed systems, whereas Python / Haskell / JS tend to only be used in high level wrappers.

IMO, the answer is history : they both appeared at roughly the same time (2009) and in the early 2010s they were more similar than they are now.

Because they both described themselves as "systems programming" languages -- though they had materially different definitions of the term.

Note, also, that their websites also have nearly identical taglines:

A language empowering everyone to build reliable and efficient software.

An open source programming language that makes it easy to build simple, reliable, and efficient software.

(Emphasis added.)

Agreed. To me, Go is a competitor to in the Java/C# kind of space: pretty normal OOP, libraries included, GC, faster than a Ruby but not as fast as C, etc.

5 Likes