Google's Rust Style Guide
google.github.io103 points by kaycebasques 2 hours ago
103 points by kaycebasques 2 hours ago
Can anyone expand on the chromium specifc guidelines on super tiny crates, particularly no nesting of modules/source files?
That feels like the ~2010 era of people saying that functions should be as small as possible. That lead me to reviewing a lot of code where every function was one or two lines and you couldn't actually see what was going on anymore through the layers of unneeded abstraction.
I want to give chrome the benefit of the doubt, but that seems really goofy.
In Cargo-built Rust, a crate is costly in terms of abstraction because it needs its own directory, Cargo.toml, src/ subdir, etc. In the Google build systems I've worked with in the past (and it looks like Chromium follows) they instead put source files in the same directory mixing languages and with finer-grained libraries as they see fit.
Given that a crate is the unit of build parallelization in Rust, there's a benefit to more crates especially when they don't cost much cognitive overhead. You could imagine using crates in the way you'd typically use separate mods in a normal Rust project.
I dug around in their code search to find some examples but didn't see much Rust in there, seems still early. I think https://source.chromium.org/chromium/chromium/src/+/main:tes... has ~4 Rust files that end up separate crates though. (One of them defines a proc macro so even in a Cargo built Rust project it would need to be in its own separate crate, I think!)
It looks like there's some macro-based import that does import by path, so crate names are generated:
https://source.chromium.org/chromium/chromium/src/+/main:tes...
You get stricter enforcement of public APIs and dependencies. You can't import anything you haven't declared as a dep, and cycles are impossible. Rustdoc by default shows only your intended public API.
OTOH if you have one crate with lots of modules, it's tempting to import anything anywhere and use pub(crate). Rustdoc needs to be configured to show private items if you want to see internal APIs.
Maybe one or two line functions are a totally different scale than "all source code files in a crate"? So like, one is problematic in a way the other is not. And the guidance is "prefer small," not "always super tiny." See: "Larger crates are allowed" later on. And also see: "Rationale: Fine-grained library targets are recommended in Chromium due to the massive size of our codebase, non-local effects of adding dependencies in the build graph, and to improve performance of parallel compilation and build caching."
It might have to do with optimizing compile times. A crate is the unit of compilation, so small crates increase the likelihood that you won't end up recompiling a lot of unrelated code.
I guess smaller crates and avoiding nested modules could also help optimize for making the code greppable by coding agents without blowing up context windows.
This being Google, I assume everything goes into a single gigantic monorepo that gets thrown at Blaze. If the unit of compilation is the crate, it makes sense for them to prefer that crates are as small as possible.
The granularity of crates shouldn't really impact what kinds of abstractions you build. You can still have as many modules and types as you need, and as big of functions as you need, but its saying you should organize the modules into separate crates instead of one large crate. They even call out the trait coherence rules, saying that you can just make your library bigger instead of forcing a more awkward design in the pursuit of a smaller crate.
I think one benefit of small crates is that it gives you more granularity in linking and dependency graphs, which is especially relevant for rebuilds. At a previous job we had a monolithic "utilities" crate, and this caused problems when you tried to depend on it for the IP address utilities but this brought in the radio frequency utilities. When one of these submodules got an update the versioning would excessively propagate downstream to every consumer. If this was organized as small "net-utils" and "rf-utils" crates then maybe it would not have been as much of an issue.
> Type names should be imported and used unqualified
This just pushes people to have redundant information in types (`IoError` instead of `io::Error`).
Unless a type is widely recognized (like `HashMap`), I prefer to have them fully qualified so I have the contextual meaning for it. If I am working with a generic name like `Source`, what does that mean? I shouldn't have to look up in the imports to understand the code (or only understand it through an LSP).
Reducing imports also reduces unnecessary merge conflicts.
Honestly I think having blanket rules in either direction is a bad idea. Sometimes it makes sense to qualify things, sometimes it's clearer if you don't.
It says below that that in cases of things like `io::Error` it should be used as that though, as in “cases of ambiguities”. It specifically speaks of not using `regex::Regex` but just `Regex` which seems more reasonable to me.
Getters and setters is the one I'm most at disagreement with.
// Mine
let label = Label.text("Hello Wold");
let label_text = label.get_text();
// Theirs
let label = Label.set_text("Hello Wold");
let label_text = label.text();
A method is a way to accomplish a specific task. Emphasis on specific not generic. The getter task is to always return. The setter task is specific. So the method should be the setter - `text`, `color`, `fill`. In Rust the getter can't have same name, so prefix it. Not the other way around.Their style is pervasive in Rust, such as in the standard library, so I would personally apply a when-in-rome philosophy. FWIW something like `.text("hello")` I would expect to see in a builder-pattern but not in a setter for an object that's already built.
That being said I don't particularly understand your conception of a method. They are both methods. The getter ought to have a shorter name since it is probably called more frequently and because it inherently has less of an impact -- this goes along with the principle that names that demand attention should be larger and easier to notice.
My use case is a TUI framework (https://www.incredible.rs/). The setters configure elements in a chain-able manner. I grappled with the rust convention and decided to go the other way. Rational as mentioned.
But this made me think...
> "The getter ought to have a shorter name since it is probably called more frequently"
So i checked. Rough agent driven counts:
https://github.com/ronilan/incredible-flappy 407 setters and 183 getters.
https://github.com/ronilan/rusticon 546 setters and 5 getters
https://github.com/ronilan/shape-sorting 688 setters and 33 getters.
And in a code editor with a lot of ui configurations based on reusable elements 2865 setters and 206 getters.
In reactive apps on state handlers call on setters with state values. No getters involved...
That means those are probably builders and not setters. Do they change an existing object or a newly-constructed or to-be-constructed object?
They are setters. They modify an element after instantiation. Mostly as part of the initial build, but then also in the event closure. Under the hood, a struct with interiorly mutable fields.
I think which to use in general Rust code depends on the purpose of your type.
A builder type like `Command` will have unqualified setters and `get_` qualified getters.
For record-like-structs, I think unqualified getters becomes preferred and `set_` qualified setters.
This style is aligned with protocol buffers, which is aligned with the style of protos in C++.
This is nice, I have been lurking on google and meta rust projects, mimicking and picking style by prompting LLMs to distill it, taking a look at fmt & clippy configs helps too.
But it wasn't as coherent and reliable from project to project like this guide. Kudos to google on this one !
Much of this is very standard across the Rust ecosystem but it's very helpful to have it all in one place.
At this point, is anybody writing new C or C++? It seems like they are sunset languages even at the big corps.
I'm pretty sure most big software projects (Windows, Linux, Chrome, gcc, LLVM, AAA game engines, ...) are still writing a lot of new C and C++. Pretty much everyone in the embedded world is as well.
As a solo programmer, I still prefer C and C++. In fact, as I've incorporated LLMs in to my workflow, I've been increasingly drawn toward C and its simplicity. A lot of the QoL features of C++ simply aren't needed when you're writing less code manually.
Unfortunately for me, yes. Some companies are very risk adverse and would rather stick with the devil they know. They have no idea what they are sacrificing.
Far from it. Until Rust can read C++ code seamlessly, there will be more code written in C++ than Rust for the foreseeable future. HPC, Finance, AI, Games, Databases, Hardware all continue to be written in C++.
Cloudflare is all in on Rust, it's used everywhere by default, and C++ leftovers are being actively torn down.
Games, anything that depends on LLVM, GCC, CUDA, SYSCL,....
Ah and Rust's compiler backend dependency on LLVM and in the future GCC as well.
Today I went over a TODO comment from 2007 in a C++ codebase that is still evolving very vividly, year after year. Trust me, for well established projects C++ is there to stay.
C/C++ is still relevant for HPC, where you want to carefully optimize memory management.
Hate to break it to you but Rust is equally capable of doing all the same memory management optimizations.
I mean you can, but C/C++ is way more ergonomic for dealing with memory layouts.
C++ seems alive and well in the defense space. The big contractors near me have tons of C++ job postings and I don't think I've seen a single one looking for Rust.
Do you know if the code bases are of the kind where dynamic memory (among many other features) is disallowed?
Some of them, probably.
From the job postings, many of them seem to be physics simulations of various kinds where (in my experience) memory is allocated on the heap without a second thought. Well, there are second thoughts, but those second thoughts are about performance.
Yes mine is, because they have a huge amount of C++ already and none of it is publicly accessible so security isn't a concern. (Obviously there are many other reasons to prefer Rust, but that is a big one.)
grownups with important jobs write C
Are you just being snarky, or do you have something more specific to say about something that's choosing C?
Considering that it's been 54 years, and we've yet to find any human being, any at all[1], who can write C without UB, I'd say that writing C in 2026 when there's any other option is basically misconduct and a good case could be made that if the code touches money in any way, then it could be a SOX violation too.
Writing C today is like still writing Cobol. Yes, if you are adding a new type of savings account to your bank, and the rest is in Cobol, then sure write it in Cobol.
Some microcontroller projects may have an ecosystem in C that makes other options harder in practice, but it's still a worthy investment to not use C. There's a reason phone baseband firmwares are moving away from C.
[1] No, not even djb, who people like to bring up.
> Considering that it's been 54 years, and we've yet to find any human being, any at all[1], who can write C without UB
Undefined behavior does not mean that a language is useless. C is quite nice to write as an abstraction over assembly, and I highly recommend writing C code and thinking about (and checking) what assembly it compiles into.
Also, it is possible to verify that the types of UB that you are referring to do not occur: see the seL4 project, which provides machine-checked proofs for an OS kernel that no execution can reach a state that is undefined by the language specification.
> Undefined behavior does not mean that a language is useless.
Never said it was useless. But it's pretty damning that literally nobody can write correct code in the language. And my point is that it's been enough time that it can't be seen as a skill issue.
> C is quite nice to write as an abstraction over assembly, and I highly recommend writing C code and thinking about (and checking) what assembly it compiles into.
Absolutely. I think in order to understand programming you need to be able to write C, and be able to read assembly.
C isn't "high level assembly", with the whole discussion about the spec talking about the abstract machine, but one does not need to be a C language lawyer to be a good programmer.
But to your point about checking the output: That goes for Rust too, and godbolt.org supports Rust too, for this workflow.
So I'm not saying C is useless. But I am saying that if someone were to decide to write their greenfield project in C, then if it plans to have actual users (as opposed to a fun project), then it's basically misconduct.
Cf. Steve Gibson writes his software in assembly, still. Because he enjoys it, and his enjoyment is the primary user. I respect that. But I would NEVER hire someone to write whole applications like that in assembly. Or C.
> Are you just being snarky,
They aren't being snarky, they're stating a fact. Rust, rounding to the nearest percent, does not exist. It's a trendy language among the Silicon Valley types that HN draws, but 99.9% of the world runs on C/++, OSes written in C/++, and language VMs implemented in C/++. Maybe some day it will change, but hanging around here too much will give you a very skewed idea of how widely adopted it is.
Well, "grownups with important jobs write C" can be taken in two ways. Non-snarky, sure. There are MANY people who write C professionally.
Not as many as there are Python, Java, JS, or C++ programmers. Depending on the survey, C seems to be neck and neck with PHP.
I read the comment the other way, though. The way that says that those other more popular languages are not serious, and NOT for grownups with important jobs.
Edit: actually, Jetbrains 2025 survey has C neck and neck with Rust: https://www.jetbrains.com/lp/devecosystem-data-playground/ . Both "below the fold" and less than 10% of Java.
Python, Java, and JS are all implemented in C/++. C++ is an extension of C. Taken strictly, sure, not everyone is literally writing C. But C powers everything. It is still the systems language of the world, that is the foundation of all of our systems, including both embedded and phone/PC OSes. Then there's a bit of COBOL and Fortran for mainframes, Ada for military hardware, and a whole notta Rust anywhere.
Think about what Rust software people actually use. Codex CLI, uv, ripgrep, and what else? That's three pieces of software, all development tools for development nerds. Normal people aren't engaging with any of this stuff. Your metaphorical grandma has never used software written with Rust in her life.
Cobol powers the world's money and international travel. Not sure how that matters.
> Think about what Rust software people actually use
More and more Chrome, Google, Android, Cloudflare, Prime Video, and phone basebands, parts of Linux kernel, and many other things.
Normal users literally use those all day every day.
Are they 100% Rust? Of course not (well, I don't actually know if some phone basebands are, by now. Naturally very closed source). But they're not 100% another-language either.
If C disappeared from the world, the world would stop, yes. Same with Cobol. Same with Java. Same with C++. Same with assembly.
If I were to guess (completely without basis for my guess) about the number of lines of code that normal users exercise in a normal day (counting each line just once), my bet would be on Java or JS.
Would the Java be able to run without the C code? No. But normal users would not be able to do anything if only C was left. And all banks would be gone.
And in any case C would not be able to do anything without transistors.
Rust is in use in more places than you may expect. Does the hypothetical grandma use Windows' kernel? Android? Firefox? Chrome?
1% of code in some obscure module that's barely used being written in Rust does not give one claim to those things being written in Rust. Even Firefox is only 10% Rust despite the language being designed by Mozilla, and they abandoned their project to write a new browser engine in Rust.
It's not "some obscure module" that is written in Rust. Just some examples I know of:
- Chrome currently uses https://github.com/googlefonts/fontations to implement its font handling, and text is the main thing on most web pages.
- Windows' DirectWriteCore for font handling is also now written in Rust.
- Firefox's whole CSS engine and GPU 2D rendering engine are written in Rust.
What is your point?
I pointed to a jetbrains study, and then there's a stackoverflow survey[1] showing C neck and neck with PHP at 11th place among professional developers.
We all know there's lots of important C code out there. I don't see anyone going "RIIR!!!" in this thread.
But obviously yes, the 11th place language will have MANY programmers working on it. Not as many as JS by far. But many. In that survey Go is just after PHP. There are also many many Go programmers.
We are not yet at risk of running out of C programmers, like the Cobol situation. Nor do I want us to.[2]
But what point are you trying to make by so strongly defending C and the comment "grownups with important jobs write C"?
[1] https://survey.stackoverflow.co/2025/technology#most-popular... [2] relevant comment: https://news.ycombinator.com/item?id=50187384