Rust beginner notes & questions

Debating technical merits (or demerits) is fine, but I noticed a theme in some of your posts, which basically goes like this: "The Rust team are a bunch of grizzled old C++ hackers who've never used an actual modern language, so therefore Rust has failed to incorporate the awesome parts of modern languages, so therefore Rust is basically just C++ 2.0 (and therefore has bad APIs)."

However, that's not true. Rust was originally far less like C++ than it is today. The Rust language team are deeply experienced with many languages (including some Haskell experts!).

The Rust language team are very smart, and generally know what they're doing. They are constantly analyzing what other languages do (either to steal good ideas, or to avoid mistakes!) Yes, there are some non-ideal APIs in Rust, and yes there are missing features, but I don't think it's fair to characterize the Rust team as being short-sighted C++ fans who design bad APIs.

There's many different perspectives and philosophies that go into Rust's design. Everybody has different parts of Rust that they dislike, because people have different perspectives and priorities. That doesn't mean that Rust's design is objectively flawed.

Most of the designs in Rust have good reasons for why they are that way. Most of the time it's because of memory safety or performance (including in deeply constrained embedded environments), something that modern languages rarely need to worry about.

Sometimes it's because people need an API now, so they design a low-level API which solves the immediate problem, with the intention to add in a higher-level API later. That is not bad API design, it is not wrong. In many cases it is correct: layered APIs are important for flexibility and performance. Being able to precisely state the exact behaviors and intentions in the code is a good thing. Generalization and flexibility don't automatically lead to better APIs (though of course sometimes it does!).


Another theme in your posts is the idea that "this should be in the standard library, the fact that it's in a crate is a massive failure of the language". This is once again a matter of perspective and priorities. Language designers have generally come to the conclusion that thick standard libraries are not a good idea, and having a strong third-party package system is superior.

There's many reasons for this:

  1. Each crate can be versioned separately (unlike the standard library which is monolithic).

  2. Having a thin stdlib means that users only download the things that they actually use.

  3. Breaking changes in crates are much more palatable than breaking changes in the stdlib.

    If a bad API gets put into the stdlib, it's stuck there basically forever. Whereas crates are more nimble and can actually change and improve.

  4. It's possible to have multiple incompatible crates being used at the same time (e.g. foo version 1.0.0 and foo version 2.0.0), whereas that's not possible with the stdlib (at least not with Rust's design).

  5. Putting the burden of creating APIs on the community means that the Rust language team can spend more time improving the design of Rust itself (e.g. impl Trait, async/await, NLL, better tooling, etc.)

This is a pretty well-known result in the Python community, where they have the expression "libraries go into stdlib to die". There's been many instances where the Python stdlib added in some reasonable code (such as for HTTP servers), but in the end it's rarely used, instead Python users use third-party packages instead (because they are superior to the stdlib).

This has even happened in Haskell! It's commonly acknowledged that Haskell should have used the Text type rather than the String type, but this is basically impossible to change: the stdlib (and by extension a large amount of Haskell code) relies upon the String type.

It's often very hard to predict in advance which APIs are good, and which APIs seem good now but will become bad later. So rather than having a large stdlib (which is known to be bad), Rust instead takes the opinion that the stdlib should be as thin as possible, with as much functionality as possible put into crates.

One of the benefits of the stdlib is that it's easily accessible. However, that's negated because using a crate is only slightly harder than using the stdlib:

  1. You have to find the crate (which is easy thanks to crates.io)

  2. You have to add a single line to your Cargo.toml

  3. You have to put an extern at the top of your lib.rs or main.rs (this requirement will be removed with the Rust 2018 module system)

Another benefit of the stdlib is that it's stable and reproducible. However, the crates are version-locked, so they are also stable and reproducible, thus negating another benefit of the stdlib.

Another benefit of the stdlib is that it has a nice documentation system. However, third-party crates use the same doc system as the stdlib. It's really nice that the docs for crates are standardized, which makes them feel a lot more "built-in" than in some other languages. And unlike in some other languages, Rust has a strong culture of crate authors actually writing docs in the first place.

So, these are the only downsides to third-party crates:

  1. They might be less maintained.

  2. They might be more poorly written (assuming the Rust language team are better programmers than the average crate author).

  3. There might be multiple incompatible crates that accomplish the same task.

There's not much we can do about point 1, aside from encouraging more maintainers. Though popular crates tend to be pretty well maintained regardless.

As for point 2, I don't think it's a problem in practice. It's true that there are some poorly written crates, but at least the popular crates tend to be high-quality.

As for point 3, it is a legitimate concern, however in practice it works out well. In general what happens is that people publish a lot of different crates, and eventually one of them emerges as the "winner" and everybody gravitates towards it. In other words, certain crates become "blessed" by the community, and thus become just as pervasive as the stdlib. You can see that with tokio, futures, serde, nom, etc.

Yes it's more organic and messy than the stdlib, but that's not a bad thing: when people are experimenting with different ideas and implementations a bit of mess is unavoidable. Trying to prevent that messiness just creates stagnation and results in bad APIs / implementations.

I think it would be a good idea to have a website somewhere that lists all of the "blessed" crates, to make it easier for Rust beginners to acclimate themself to the Rust ecosystem: right now a lot of that knowledge is locked within people's minds.

18 Likes