Extra Meal How You Can Learn From This Column and Whether Rust Is Worth Learning

Extra Meal: How to Learn from This Column and Is Rust Worth Learning? #

Hello, I’m Chen Tian.

Since the course was launched online, I genuinely did not anticipate so many students being eager to learn Rust. First of all, thank you for your support, encouragement, and feedback.

In the past few days, while handling the comments, I have received many unexpectedly in-depth statements and questions, such as from students @pedro, @有铭, @f and so on. Not only have they made me truly feel your enthusiasm, but they have also strengthened my determination to teach this course well. In this extra meal, I will talk in detail about some of the issues that students are more concerned about.

First, I will discuss why Rust solves many of the problems we developers encounter in practice, problems which most current languages have not solved well, from the perspective of controlling code defects. Then, we will talk about why the future of Rust is promising, and by the way, compare Rust with Golang since this is a question asked frequently in the comments. Finally, I’ll share some Rust learning materials.

Code Defects #

From the perspective of software development, to provide functions with a good user experience, the most basic requirement is defect control. To control defects, we have defined various processes in software engineering, from code formatting, to linting, to code review, and then to unit tests, integration tests, manual tests.

All these measures are like funnels, constantly screening the code, filtering out defects layer by layer, in order to deliver perfect software to users. I made an illustration that categorizes the possible defects that may occur in the development process; let’s look at it from top to bottom:

Image

(The images in the course are all drawn using excalidraw)

Syntactic Defects #

Firstly, when we start coding, there might be minor problems at the syntax level, such as beginners not being too familiar with certain syntax points, and senior engineers might make syntax errors when using less commonly used syntax.

For these defects, most programming languages will provide detailed prompts as you write code, telling you where the syntax error occurred.

For Rust, it provides the Rust Language Server/Rust Analyzer to report syntax errors promptly. If you use third-party IDEs like VSCode, you will have integration with these tools.

Type Safety Defects #

Then, there are defects related to type safety. These require the language’s type system to help discover defects, so most type-unsafe languages are helpless against these errors.

Taking Python/Elixir as examples, if you expect a function’s parameter to be type A, but you actually used type B, this error can only be checked when your code is truly running, significantly delaying the moment the error is found.

Therefore, many scripting languages now tend to encourage developers to write more type annotations. However, since it is not a native part of the language, it’s difficult to enforce. When actually writing script language code, pay special attention to type safety.

Memory and Resource Safety Defects #

Almost all languages have memory safety issues.

For languages that manage memory automatically, the automatic management mechanism can solve most memory problems, preventing situations like memory being used and not released, using released memory, hanging pointers, etc.

We mentioned before that most languages, such as Java/Python/Golang/Elixir, have solved memory safety problems through the language runtime.

But it’s only most of them. For example, memory leaks that exist logically due to design defects—like a cache with TTL that is not designed well, causing the content in the table not to be deleted after timeout, leading to continuous growth in memory usage—are still not solved by any language. They can only be resolved as much as possible.

The same goes for resource safety defects which are problematic in most languages, such as file/socket resources. If allocated without being properly released, it leads to resource leaks. Languages that support GC can’t do much about this, and developers often have to manually release resources.

However, releasing resources is not simple, especially when handling exceptions or abnormal workflows, where it’s easy to forget to release allocated resources.

Rust can be said to have fundamentally solved key memory and resource safety issues. It ensures memory and resources are released at the end of their lifetime through ownership, borrow checker, and lifetime checking.

Concurrency Safety Defects #

This issue occurs in languages that support multithreading. For example, if two threads access the same variable without proper critical section protection, concurrency safety issues can easily occur.

Rust solves this problem through ownership rules and the type system, mainly by two traits: Send/Sync.

Many high-level languages will shield the concept of threads and only allow developers to use the language’s runtime to ensure concurrency safety, such as Golang, which requires the use of channels and Goroutines, or Erlang, which can only use Erlang processes. As long as you work within its framework, concurrency handling is safe.

This can handle most concurrency scenarios, but in certain situations, it can lead to inefficiency or even block other concurrent tasks. For example, when there is a long-running CPU-intensive task, using a separate thread is much better.

There are many methods to handle concurrency, but most languages, for the sake of concurrency safety, have shielded many means, preventing developers from touching them. However, Rust provides you with these tools and also provides robust concurrency safety assurances, allowing you to use the right tools safely in the appropriate scenarios.

Error Handling Defects #

Error handling, as a branch of code, can account for 30% or even more of the code volume. In practical engineering, when functions are nested frequently, the whole process can become very complex, and if not handled well, defects can be introduced. A common problem is that the system has erred, but the thrown error has not been processed, leading to the program crashing in subsequent operations.

Many languages don’t force developers to handle errors. Rust uses the Result type to ensure the type safety of errors and forces you to deal with the returned value of this type, preventing developers from discarding errors.

Defects Caused by Coding Style and Common Errors #

Many languages provide code formatting tools and linters to eliminate these defects. Rust has built-in cargo fmt and cargo clippy to help developers unify code style and avoid common development errors.

The next three types of defects can’t be helped by the language and compiler.

  • For logical defects, we need to have a good unit test coverage;
  • For functional defects, we need enough integration tests to test the main functions used by users;
  • For user experience defects, end-to-end testing, and even manual testing are needed to discover them.

From the above introduction, you can see that Rust helps us to nip as many defects as possible in the bud. Many defects that Rust solves during compilation, such as resource release safety, concurrency safety, and error handling, don’t have complete solutions in most other languages.

Thus, Rust allows developers to focus their time and energy as much as possible on optimizing logical, functional, and user experience defects.

The Cost of Introducing Defects #

Let’s look at the benefits of Rust’s approach from the perspective of the cost of introducing defects.

Image

Firstly, it’s impossible for any system not to introduce defects.

If the defect is found while writing code, the correction time is at the millisecond to second level; if detected during testing, it may be at the second to minute level. As such, if defects are only found after the code review to integration into the master, the time cost is very long.

If it’s not discovered until users are using it, that can mean weeks, months, or even years. When I was working on a firewall system, bugs of a new feature were often not exposed until a year or even two years later in the user’s production environment, and resolving defects at that time is costly.

So from the beginning of its design, Rust aims to check out as many defects as possible for you during compilation, at the seconds and minutes level, and allow you to modify. So as not to carry defects into subsequent environments, it ensures code quality to the greatest extent.

This is why, although beginners in Rust need to struggle with the compiler in the early stages, it’s worth it. Once you get past this hurdle and can compile the code successfully, there’s generally not much concern about the safety of your code.

Judging the Prospects for Language Development #

Many students are concerned about Rust’s development prospects and ask about comparisons with other languages, often talking about what languages Rust will replace now or in the future, whether Rust will dominate the frontend and backend, and so on. I don’t think so.

Every language has its respective advantages, disadvantages, and suitable scenarios, and it’s not about who will definitely replace who. The formation, prosperity, and decline of a community are long-term processes. As with the “world’s best language PHP,” it is still growing tenaciously.

So how do we judge the development prospects of a new language? Below is data processed with pandas from modulecounts, which shows the number of libraries of mainstream languages. You can see that in early 2019, the starting point for Rust crates was not high, just over 20,000, but more than 60,000 two years later.

Image

As a new language, although Rust’s ecosystem is not numerically high, it has consistently led in growth rate, with the past two years’ growth speed almost being double that of second-place NPM. Unfortunately, Golang’s libraries don’t have a good statistical channel, so I can’t compare Golang’s data here. But the comparison with languages such as JavaScript/Java/Python is enough to illustrate the potential of Rust.

Rust and Golang #

Many students are concerned about the comparison between Rust and Golang. There are many detailed analyses online, this one is quite good to take a look at. I’ll also briefly mention here.

The primary areas where Rust and Golang overlap are in service development.

The advantage of Golang is simplicity and quick learning, as the language has already arranged a concurrency model for you to use directly. For development teams that are under tight schedules, have many services to write, and do not care about ultimate performance, Golang is a good choice.

Golang is designed from the beginning to meet the needs of modern concurrency and thus uses a runtime and a scheduler to schedule Goroutines. In Golang, memory does not need to be manually released by developers, so there is a GC in the runtime to help manage memory.

Additionally, for the sake of syntactic convenience, it does not support generics from the outset, and this is currently the most criticized point of Golang. Once the system becomes complex to a certain extent, each type will need to be implemented repeatedly.

Golang might add support for generics in version 1.18 in 2022, but generics are a double-edged sword for Golang. While they bring many benefits, they will also greatly damage the simplicity and rapid compilation experience of Golang. This might confuse developers: since Golang has become complex and not so easy to start with, why not learn Rust?

Rust’s design philosophy is the opposite of Golang’s.

Go is relatively small and has a simple type system while Rust, inspired by Haskell, has a complete type system supporting generics. For performance considerations, Rust does monomorphization when dealing with generic functions; a set of code will be compiled for every type used in a generic function. This is why Rust compiles so slowly.

Rust aims for system-level development. Although Golang wants to be the new era C, it is not suitable for system-level development. Its use is more for application and service development because its massive runtime is not suitable for bottom-level development that interacts directly with the machine.

Rust aims to replace C/C++, seeking to create better tools for system-level development. Therefore, Rust’s design requires no runtime from the outset. So what you see as runtime-like libraries in Golang, such as Tokio, are all third-party libraries, not in the core language. This gives developers the freedom to decide whether to introduce a runtime.

There’s a saying in the Rust community:

Go for the code that has to ship tomorrow, Rust for the code that has to keep running for the next five years.

So, I am very optimistic about the future of Rust. It can replace some C/C++ scenarios in system development, compete with Java/Golang in service development, partially replace JavaScript through compiling into WebAssembly in high-performance frontend applications, and easily provide safe, high-performance underlying libraries for various popular scripting languages through FFI.

I think Rust will be like water in the entire programming language ecosystem in the future, omnipresent and beneficial for everything.

Lastly, let me share some resources that I found useful while learning Rust, and I will also explain how they can complement this course.

Official Learning Materials #

The Rust community provides plenty of learning materials for us.

First is the official Rust book, which covers all aspects of the language and is the most authoritative free resource for learning Rust. However, this book is quite fragmented; some content that needs emphasis is only briefly mentioned, leaving readers still puzzled after finishing it.

I remember when I was learning the Deref trait, this segment of the official documentation stumped me:

Rust does deref coercion when it finds types and trait implementations in three cases:

  • From &T to &U when T: Deref
  • From &mut T to &mut U when T: DerefMut
  • From &mut T to &U when T: Deref

So I think this book is suitable for learning an overview of the language, but for content that you can’t understand for the moment, you need to find additional materials or master it through practice. When learning the course, you can flip through this book to reinforce what you have learned.

Another official Rust Nomicon (The Rustonomicon) discusses Rust’s advanced features, mainly how to write and use unsafe Rust, and is not suitable for beginners. It is recommended to read this book after completing the course or at least after learning the advanced content.

Rust’s documentation system docs.rs is among the most comfortable to use and the most consistent experience of all programming languages. Whether it’s the standard library’s documentation or third-party libraries, they are generated using the same tool and are very easy to read. Your own crates, once published, will also be placed on docs.rs. Making good use of these documents will greatly benefit your learning efficiency and development efficiency in your study and coding.

The standard library’s documentation is recommended to be read when you learn about a particular data type or concept. In each lecture, I will post a link to the standard library content involved, and you can do extended reading.

To help Rust beginners further consolidate the effects of Rust learning, Rust officially also published rustlings, which includes a vast number of exercises to solidify understanding of knowledge and concepts. Students who are interested and can afford it should try it out.

Other Learning Materials #

After discussing official materials, let’s look at other content on Rust, including books, blogs, and videos.

Let’s talk about a few books first. The first one is Han Dong’s “The Tao of Rust Programming,” detailed and profound, a rare Rust book in Chinese. Han Dong has a Rust video course on Geektime; if you’re interested, you can subscribe. In English, there’s Programming Rust, now in its second edition. I have read the first edition and it’s well written, comprehensive, suitable for reading from front to back, and for filling in the gaps.

Besides book-related materials, I’ve also subscribed to some good blogs and public accounts, which I’ll also share with you. For blogs, I mainly read This week in Rust and you can subscribe to their mailing list, scan topics of interest each time, and read in-depth.

Public accounts are mainly for obtaining information and learning about community dynamics. There are public accounts like Rust Language Chinese Community, and Rust Musings, which sometimes push content from This week in Rust, and even translations.

Another great source of content is Rust Language Open Source Magazine, which comes out monthly and includes a wealth of excellent Rust articles. However, I feel that the main audience for this magazine is developers who already have a certain grasp of Rust. It’s better to read the articles inside after you have finished the advanced sections.

In the Rust community, there are also many excellent video resources. Beginner’s Series to: Rust is recommended by many in the community, a series of Rust training launched by Microsoft, quite new. I briefly looked at it and it’s not bad, although it’s a bit slow, you can watch it at 1.5x speed to save time. I mainly subscribe to Jon Gjengset’s YouTube channel; his videos are aimed at mid to high-level Rust users and are suitable for watching after finishing this course.

For domestic videos, there is also a wealth of Rust training material on bilibili, which needs to be sorted by yourself. I also made a few sessions of “Programmer’s Rust Training,” which can be watched if interested and serve as supplementary material for the course.

After sharing so much, I hope you can be firm in your confidence to learn Rust. Believe me, whether or not you will use Rust in the future, just the process of learning Rust can make you a better programmer.

Feel free to share your thoughts in the comment section, and let’s discuss together.

References #

  1. To be used in combination with the course: The Official Rust book, Microsoft’s Rust series Beginner’s Series to: Rust, the English book Programming Rust for filling in gaps

  2. Advanced learning