Being Rusty: Discovering Rust’s design axioms
To your average joe, being “rusty” is not seen as a good thing. Being Rusty – with a capitol R! – is, of course, something completely different! So what is that makes Rust Rust? The Rust Design Axioms repository is an attempt to articulate the answer. These axioms are a work in progress! Please contribute your ideas on how to improve them!
For more about the design axioms, see this blog post introducing the idea.
How to structure the axioms?
There are a great number of “rules of thumb” and goals that we strive for. I’m actively debating the best way to structure the axioms. I’m updating this page to include a kind of “union” of different approaches.
Rust’s goal
My take on Rust’s mission statement – the thing we are trying to achieve – is this variation of the slogan from the webpage:
Empowering everyone to build reliable, efficient, and maintainable software
The word “everyone” in this slogan does a lot of work. A key goal for Rust is to make the term “systems programming wizard” an anachronism. Today, if you want to do low-level systems programming, you have to keep so many things in your head that it crowds out the ability to focus on higher-level domains. This makes it very difficult to do both at once. Rust’s goal is to provide structure and scaffolding so that, for most of your code, you can write high-level looking code and focus on the needs of your domain.
When you do need to drop down to low-level patterns, you should be able to do so, but in an encapsulated way that lets you build a performant, composable abstraction that will guide its users towards correctness. This way, when you are working with that interface, you don’t have to be as cognizant or focused on the low-level details.
What is empowerment?
I ponder sometimes the word empowerment. What does it mean exactly? To me it means three things (in order of precedence):
- Lowering the barrier to entry. It should be possible to get started very easily and get something that is 99% of what you want.
- No ceiling. The tool should scale to any use case. You shouldn’t have to “graduate” to a more complex tool to get the “real work” done.
- No complexity cliff. You should be able to grow to more and more complex use cases without encountering a steep step up in complexity.
Where is Rust a good choice?
Rust targets programs and domains where
- reliability
- efficiency
- and long-term maintenance
are top priorities. For other domains, Rust may still be a great choice, but you may find that it adds a bit more overhead than you would like.
What we strive for
This section is meant to capture
Note on status: Some of the axioms are tagged with . These are axioms that that I feel pretty good about and where I am pretty confident about where they fall in the ordering. Others are tagged as . These are cases where the wording may need improvement and the ordering is less clear; some of them may want to be merged with others. –nikomatsakis
- ⚙️ Reliability above all. Rust users want to be sure their program will handle the edge cases that arise in production, not just the happy path. We guarantee memory safety and data-race freedom and look for opportunities to surface other problems wherever we can.
- 🏎️ Performant, composable abstractions. We favor high-level APIs where the most convenient option is also the best one. The default style of writing things should be efficient and portable across operating systems and execution environments. We aren’t explicit for the sake of being explicit, but rather to surface details we believe are needed.
- 🔧 Low-level control and transparency. When building systems, it’s often important to know what’s going on underneath the abstractions. Abstractions should still leave the programmer feeling like they’re in control of the underlying system, such as by making it easy to notice (or avoid) certain types of operations.
- 🌟 Extensible and productive. We empower our users to build their own abstractions. We prefer to let people build what they need than to try (and fail) to give them everything ourselves.
- 🤸🏾 Accessible and supportive. Building reliable, efficient programs is ultimately a complex business. We can’t always make Rust easy, but we can make it supportive. Our tooling aims to make “best practices” easy and convenient and, where choices are needed, to explain the choices and their implications as clearly as possible. Using Rust is a great way to level up your understanding of new domain or problem area.
Some of the rules we use for this
-
Design for the long term. We aim When faced with tension
-
Target the extremes.
-
Not afraid to do the right thing. We
-
Learn from beginners. We
-
No required runtime. It should also be possible to build Rust on bare metal without any operating system or supporting runtime. There should be “no room” for a language between Rust and inline assembly.
-
Not afraid to do the right thing.
How to read the axioms
Ordering is significant. Despite our best efforts, the axioms inevitably come into conflict. If we are forced to push, we prefer to satisfy the axioms that come earlier in the list. For example, accessibility ultimately trumps all, including reliability – this is why we have a simple, workable type system that covers 99% of what you want and leave the rest to unsafe code, versus requiring full correctness proofs all the way down (but if we can make those proofs, so much the better!).
The axioms capture beliefs about what Rust users value. These axioms – and especially their ordering – are not universal. They are geared towards programs where performance, reliability, and long-term maintainence are top priorities. If these axioms don’t sound like the right balance for your project, then Rust may not be the right choice.
The axioms are not absolute. To start, these axioms should be treated as a living document that can grow and change over time. But also, the axioms don’t apply equally in all situations. For example, in some high-assurance domains, reliability takes precedence over accessibility; when designing aspects of Rust that are targeting those areas, it may make sense to develop more specialized versions of the axioms.
How to contribute to the axioms
These axioms are a work in progress and we would very much like your help to make them better! The contribution page has instructions for how to participate.
–
Rust Design Axioms is marked with CC0 1.0 Universal
Examples
This page contains examples that illustrate the axioms at work. Some of these are things that we do (or choose not to do) because of the axioms. But more interesting art the examples of where the axioms are in tension.
Examples that exemplify the axioms
Things we do (or choose not to do) because of the axioms
Examples that support the ordering
- “Accessible” over “Reliable”
- Rust’s pattern around unsafe code is an example where these came into tension and we let practicality win. We tried to build a safe type system that covers 95%-99% of the code you need to write, but which is by no means exhaustive. We let people vouch for the rest with minimal fuss or ceremony. It is certainly possible to build safer systems, either by requiring full proofs of correctness or by limiting the ability to write unsafe code, but we believe those options would be far less practical.
- “Reliable” over “Extensible”
- We don’t let users overload
&&
or||
because they have special control-flow; we require macros to be marked with!
so that users are aware they may not behave like a function call when it comes to control-flow.
- We don’t let users overload
- “Extensible” over “Transparent”
- We have procedural macros, build.rs, and numerous mechanisms that let people generate large amounts of code.
- “Transparent” over “Productive”
- No implicit memory allocation (e.g.,
Box
) - Distinguishing
Rc
andArc
- No implicit memory allocation (e.g.,
- “Productive” over “Versatile”
Counterexamples where we violated the ordering
- “Productive” over “Transparent” and, arguably, “Reliable”
- Auto traits:
Contributing to the axioms
These axioms are very much a work in progress – and they always will be! We are actively soliciting contribution. For changes to the axioms themselves or the ordering between them, please open an issue on our github repository. When you do so, you’ll be offered a choice between two issue templates:
- Suggest a new axiom or a change to an axiom– what is some aspect of Rust’s design that you feel is not explained by the existing axioms? Or perhaps you think the existing axioms could be changed or combined?
- Suggest an example that supports or rebuts the current ordering – what is a part of Rust where two axioms were in tension, and which one got preference? Does that support the current ordering of the axioms?
For other changes, PRs against the site are welcome:
- Fixing typos
- Expanding on FIXME or TODO sections
- General improvements to the prose that don’t change its meaning
FAQ
Here are some guidelines for authoring or suggesting axioms.
When does it make sense to split an axiom into two?
Oftentimes there are two aspects of Rust that could be combined into a single axiom or which could be separated, and it’s a bit hard to know which you should do. In general, it makes sense to combine axioms together if they seem thematically related, because fewer axioms are better; but if these two aspects might be in tension with one another, or the precedence of one is different than the other, then we should break them out.
As an example, I have currently made productivity one of Rust’s design axioms, and in there I mention that, because we try to keep productivity high, we design for programs to be portable by default. But it’s possible that portability should be broken out into its own axiom. The main reasons to do that would be if (a) portabiilty is in tension with productivity or (b) we give portability higher or lower precedence than we give other aspects of productivity.
FAQ
What are the axioms for?
The axioms are meant to capture and ake explicit the assumptions and intuitions that we use when building Rust. When making a decision, whether it’s a question of language design or something else, we implicitly bring assumptions, intuitions, and hypotheses to bear, often without noticing. You might think, “Hmm, maybe we could do X? Oh, but if we did that, it would mean Y, and I don’t want that, scratch that idea.” The goal for design axioms is to capture those moments – whatever Y is right there, it’s one of the design axioms we are using — and write them out explicitly. Once we have the axioms written out, they can be used when facing future decisions. This in turn helps to bring alignment to a group of people by making those intutions explicit (and giving people a chance to refute or sharpen them).
What is the scope of the axioms?
The axioms are meant to explain why we designed Rust the way we did. They primarily cover the technical side of Rust (the language, standard library, tooling, etc) but they also apply to the way we run the project (open source, our release model etc). It’s possible this should be brought out more explicitly. As an example point of inspiration, I quite appreciated how Hyper’s design tenets intermix elements of community, beginning with Open.
Why do you call them design axioms? Aren’t these the same as (tenets | guiding principles | whatever)?
The term design axiom is inspired by proof systems, where axioms are the things that you assert to be true and take on faith, and from which the rest of your argument follows. Our goal is to capture this for Rust: What are the starting assumptions that, followed to their conclusion, lead you to design Rust? The more clearly we can articulate those assumptions, the better we’ll be able to ensure that we continue to follow them as we evolve Rust to meet future needs.
I have some ideas for how to improve the axioms! How can I help?
See the contributing section!