C/C++ vs Rust vs Go vs Python: Can you really compare them?

Let me start with a slight background about myself. I am an IT systems engineer who started writing code in 2014 and spent the first 3–4 years extensively coding in Python. Then I moved onto C and wrote C for about a couple of years. I spent the last few months submerged writing a simplistic lock-free memory-based inter-process communication mechanism to pass raw network packets in Rust. And currently I am learning more about modern C++ (note I say “modern”) to implement an asynchronous message broker. All this has been interspersed with forays into the Go language where I have been trying to write a proxy-less service discovery system (in reality the proxy-less part comes because I intend to integrate it with a modified version of OpenNetVM).

The next question is why I decided to write another “comparison” piece. To be honest, this is not a comparison piece at all, and I have no intention of ever writing a comparison piece for the simple reason that I am not capable enough. However, I have seen enough such pieces during my reading on the Internet. Many of them are decent enough but the majority of them reads like absolute junk, in my opinion. The proverbial last straw was when I came across an article yesterday that put forward claims like “JavaScript is better than C++” and “Do systems programming in Go”. Again, to be honest, I really only read the starting of the part where the author talks about C++ and even to me, a C++ semi-noob, it looked like there is no real experience behind the words — and people were actually reading this and maybe getting influenced. That was finally what prompted this piece.

Now let me assure you that there are very good reasons to never look at C++. Almost as many reasons to pick up JavaScript. However, I can’t think of good application overlap — no one really uses C++ to write frontend or even backend web apps. Similarly, Go is a great language to write system programs until you need to squeeze every ounce of performance out of the system (or if you are in the embedded zone).

Anyhow, my rants apart, this piece is about my take on these languages.

Let us start by looking at Python:

  • It is extremely easy to learn and start being productive with
  • Debugging is simpler because one can, mostly, run the code, line by line, through the interpreter and look at the intermediate results
  • You get what you write — no compiler is optimizing anything (that can be both good and bad)
  • There is a large community around Python that has already built most of the tools one might want to use in a project, more than once
  • With the advent of libraries like PyTorch and TensorFlow, Python really shines with data analytics/machine learning like applications
  • There are also amazing web development frameworks like Django and Flask but I have not really used them much
  • Python is very loosely typed (which again can be both good and bad); returning multiple values from a function is simple and so on

The second language to look at is Go:

  • Go is another language that is rather easy to learn; in some cases, for example concurrency, Go constructs can be easier to learn than Python’s
  • Go is a glove that fits many hands; one can write web app, other applications or even low-level programs as long as the prime requirement is not the fastest execution time. However, that doesn’t mean that Go is slow. It is significantly faster than Python and if the Internet is to be believed, then can be almost as fast as C/C++/Rust in certain cases
  • Go is garbage collected — which means that developers don’t need to manually manage memory; furthermore, the garbage collector can be turned off too but again, I don’t have experience with that but even with that, Go has an in-built scheduler and I don’t think one can disable that and write code directly on the system
  • On the other hand, Go is somewhat restricted — there are many features available in other languages like Rust or C++ that doesn’t exist in Go — for example operator overloading and inheritance. The Go philosophy is to avoid complexity
  • Go implements “green” threads as a core part of the language making asynchronous programming as simple as multi-threaded programming

Next is C:

  • If you are looking to really learn about systems learn C but it has a steep learning curve since one needs to understand the underlying system
  • Linux/Unix operating systems are all written in C
  • C provides unabridged access to memory which gives programmers a lot of raw power but also a lot of opportunities to make mistakes
  • There is a large community support and third-party libraries to do things like multi-threading (pthread) or event-based programming (libevent and inotify-event) — these have their own learning curve
  • The biggest troublemaker in C is the requirement to manage everything on the system manually

Now let’s look at Rust:

  • Rust is a language that has very strong memory protections which tends to prevent many errors common in C; understanding this is probably the hardest part when learning Rust
  • Rust forces developers to be aware of things like move semantics, mutability, ownership,exclusive write access, race conditions, RAII* from the get-go
  • Most error checking is done at compile time which also check for the above
  • Rust is extremely fast
  • Rust community is growing at a fast pace and the language is maturing similarly, though I think it’s not fully mature yet
  • Absence of certain features like function overloading can be slightly bothersome but might be overcome with generics

Finally, let’s tackle C++:

  • It’s a very popular opinion that C++ is too vast — an opinion that I also believed in for a long time. And to some extent that is true. But I have come to view C++03 and C++11/14/17/20 as two different languages (I, and I believe many others, refer to C++11/14/17/20 as modern C++)
  • Up to C++03, the language is mostly object-oriented programming added to C. But C++11 onwards, C++ has included concepts like what Rust has (point 3b). Unlike Rust, C++ doesn’t force the developer to be cognizant of these issues; but as one’s experience with programming grows one starts using these features
  • However, unlike Rust, C++ still doesn’t have immutability and exclusive write access by default (these two are very useful in reducing certain kind of bugs but I have also found them somewhat restrictive under certain conditions, though that might be chalked up to my inexperience)
  • One of the main reasons C++ feels so vast is that the language is continuously tweaked to keep up with modern demands while keeping backward compatibility intact — C++00 would compile fine on a modern C++ compiler as would modern C++)
  • The modern subset of C++ (modern C++) is quite a useful language — a popular criticism of this view is that one person’s definition of a “subset” can differ wildly from another; while that might be true, the overall framework still remains the modern C++ (or C++03)
  • Another popular criticism is that C++ compile times are too long. My own experience is that modern tools like Meson and Ninja can cut down the compile time to a great extent, but this may not be always true
  • The biggest criticism I have for C++ is that it can be extremely hard to read C++. Some of the reasons are archaic like sprinkling code handsomely with preprocessor directives but also due to the presence of multiple inheritances, C++ definitions and declarations can be all over the place. I believe that Rust shares the second part of this criticism.

Overall, I truly believe that comparing languages is wasteful activity due to the sheer number of variables involved. Personally, I will pick Python to write system scripts automating something or the other and for data processing. Go feels natural when I really don’t care about speed and want to build a simple system — typically a backend to run my experiments or some other system-ish service. C is still my staple because I do a lot of work where interacting with the operating system is critical. As for Rust vs C++, I am undecided. I feel Rust simply is the stricter more restricted version of modern C++. I also think Rust is still not as mature as it should be (but I am willing to agree that this might be a fallacy on my part). Finally, I correlate flexibility and feature availability with a language’s power. It might be difficult to wield that power correctly but I can’t look at it as the language’s fault.

--

--

Ratnadeep Bhattacharya (https://www.rdeebee.com/)

Distributed Systems researcher and engineer (grad student) at The George Washington University!