Original: The success of Go heralds that of Rust
Author: George Hosu
Translators: xiaoaiwhc1, shenweiyan, 溪边九节, 兰陌木兮, adoontheway, 蜗牛伊
From a holistic perspective, it is difficult to understand how Go has achieved such great success.
Theoretically, Go is a very poor language, even when compared to older languages like C++ or Ada.
It lacks a significant amount of compile-time checks and compile-time logic, and it lacks destruction logic, leading to many boilerplate files and runtime errors. Its interfaces are not very expressive. It has first-class data structures (slices and maps) but cannot use the language itself as a library for copying. It forces users into mutability in many cases where it is not needed. It comes with a pseudo dependency manager and lacks independent version control for standalone projects. Compared to most other popular systems programming languages (i.e., C, C++, Ada, Fortran, and Rust), it is very slow.
This is what I can think of right now, and it is easy to demonstrate. Once you delve into Go, you will find that it makes some inherent design choices that are flawed; it is a language designed for 1980, not 2020.
Nevertheless, as anyone who has ever used Go can tell you, it is a very good language. If I were stranded on an island with only three programming languages, I would want Go to be one of them.
Despite all its flaws, it allows you to write relatively error-free code with good performance. Adding dependencies to a Go program is usually much smoother than adding dependencies to a C++ program.
Why Go is Great
This puts me in a very strange position. On one hand, I can talk about how terrible Go is. On the other hand, Go is clearly a very good language.
To figure out why this is the case, we still need to return to the programmer’s perspective of solving problems, viewing the language as a tool.
Many of the problems in the modern world seem to revolve around effective network communication, safely utilizing all hardware threads, and easier development and deployment.
Eventually, there has been a stable trend where good open-source libraries permeate our lives, most of which are concise and simple, suitable for single purposes. Most Node or Python projects have hundreds of such dependencies, while most C and C++ codebases have a dozen or so. C and C++ lack any standardized package management, so libraries often become monolithic (see QT and Boost), and adding new dependencies is very time-consuming.
Open-source libraries are an important part of modern developers’ careers, but all popular systems programming languages lack package management.
From this perspective, Go has some central features that are so amazing that they overshadow all the bad aspects.
-
Go’s utilities allow you to easily download and use packages.
-
Static compilation makes it easy to port code between different environments and easily establish development environments.
-
The native asynchronous I/O mechanism allows you to easily write high-performance network code.
-
Built-in channels allow for easy and relatively safe data transfer between [g|c]oroutines.
-
The standard library and package ecosystem contain most of the libraries developers will need.
-
For almost all use cases, it is “fast enough.” It seems to find an optimal position between easy-to-use single-threaded languages like Python and Node, and older, faster behemoths like C++ and C.
In other words, Go is a language designed for open-source libraries, large-scale parallelism, and network computing.
Other popular languages lack one of these three categories.
All remaining issues with Go stem from three design choices:
-
Garbage collection instead of defining compile-time lifetimes for all its resources. This harms performance, removes useful concepts (like move semantics and destructors), and weakens compile-time error checking capabilities.
-
Lack of immutability, except for a few (native) types.
-
Lack of generics.
If these issues were resolved, Go would undoubtedly become the language of the future. However, due to various problems, some related to previous design decisions and others to the opinions of the designers, most remain unresolved.
For example, generics may be implemented in version 2.0, but the current implementation overlaps with other features (like interfaces) while being cumbersome to use and lacking features (like not being usable as return types).
Perhaps we can find a language that “checks” all the correct syntax without having to endure those poor design decisions.
Now, Let’s Look at the Rust Language
Rust happens to be a language that solves all of Go’s problems.
Based on its implicit move semantics and borrowing checks, it ultimately becomes the safest, fastest, and easiest to use language in the realm of resource management (relatively speaking; for example, the current borrowing checks are quite difficult to use, as anyone who has used it knows). It can catch most errors at compile time.
Templates and traits give it compile-time programming capabilities close to C++, and in some aspects, even better.
Finally, Cargo is also one of the best package management systems, making it easier to use various useful public libraries, with built-in versioning and project isolation features.
In other words, Rust’s tremendous success is based on its better resolution of the issues present in Go.
But what has Go done incredibly right?
-
go get and go mod are very comparable to Cargo.
-
cargo build defaults to using static compilation routes, which is basically consistent with go build.
-
The key point is that Rust currently lacks a native asynchronous I/O mechanism. However, it is said that this mechanism is coming soon. This mechanism is very different from what goroutines provide and is more like the syntax we are familiar with in Node and Python.
-
Rust not only provides native channel support between threads, but it also offers a robust compile-time thread safety checking mechanism. This means there is no risk of concurrency errors, regardless of what data-sharing mechanism you use.
-
Although Rust is a much younger language, its standard library is almost as rich as Go’s, except for (again, except for) some missing asynchronous network features. Currently, Rust’s package ecosystem is somewhat similar to Go’s.
-
Finally, in terms of efficiency, Rust is only slightly slower than C and C++ in most scenarios. However, for its design direction, this is merely a “temporary” discount. Go will always be burdened by a lack of compile-time logic and a GC-based design. Therefore, the existing significant efficiency gap between Go and Rust will only widen.
The Impact of Go
Once the async/await feature is merged into Rust’s stable version, I believe Rust will completely surpass Go, in every aspect! (Translator’s note: Borrowing checks are still a reason Rust is difficult to use; it would be best to have more implicit borrowing or better solutions.)
I believe that until Rust is truly applied in products, people will not realize how much time Rust saves you in testing, debugging, and program crashes.
The more Rust and Rust-related concepts enter the programming world, the more familiar people will become with its syntax and concepts, thus lowering the entry barrier.
I believe Rust has passed the most dangerous period of its life; it is gradually being accepted as a primary development language. Furthermore, when compared to other languages in various aspects, it almost completely outperforms them (Editor: In terms of various language features, it indeed does, but it still lags in usability). In simple terms, Rust should be the better choice in most cases.
However, human inertia is a problem that cannot be ignored; the resistance to widespread adoption of Rust comes from how to persuade developers to switch to it.
Here, I believe the sudden explosion of Go can also be similarly applied to Rust. Rust is now getting closer to a full explosion (Translator’s note: As the ecosystem matures, it is nearing the tipping point).
Some C and C++ developers who hope for a “modern programming paradigm” will also come to like Rust.
At the same time, for those looking to transition from scripting languages to systems programming languages, this is the best choice; you not only gain safety and performance, but you can still use package management tools and familiar syntax.
In any case, this is my prediction: once async/await is added to the language, we will see a flood of web application developers flocking to Rust.
High-performance open-source software that relies on the web, such as memory caches, databases, and reverse proxies, will begin to mature gradually. Many such projects have already emerged in the Go ecosystem.
Once these developers catch a whiff of Go’s simplicity in networking and concurrency, combined with C++’s speed, abstraction capabilities, and resource management, as well as top-notch compile-time safety…
Then, web developers and enterprise teams will follow suit.
Everything will be like opening the floodgates, unstoppable.
About the Author:
George Hosu https://github.com/George3d6
Open Source China is now accepting submissions!
Open Source China www.oschina.net is currently a highly regarded and influential open-source technology community, with over 2 million open-source technology elites. We promote the concept of open source, advocate open-source projects, and provide a platform for IT developers to discover, use, and communicate about open-source technologies.
We are now starting to accept submissions! If you have excellent technical articles to share, or hot industry news to report, please contact Open Source China for submission. For submission details and contact information, please refer to: I want to submit
Recommended Reading
Neo4j Announces Complete Closure of Enterprise Edition
Django Faces Development Dilemma, Aiming to Restructure and Abolish Core Team
Spring Cloud Alibaba, a Blessing for Chinese Java Developers, Extending Microservices for 18 Years
Implementing Autonomous Driving for Cars Using Tensorflow on Raspberry Pi
UDP-based HTTP/3 May Become the New Standard, Textbooks Will Need to Be Rewritten
For more details, please check the original article↓↓↓↓↓