Rust Style Guide
google.github.io
google.github.io
It’s the eternal struggle between flexibility and strictness that doesn’t really have a silver bullet answer. Or maybe it’s better framed as “flexibility, safety, backwards compatibility, pick any two”?
There are reasons why Google pays this price! But I think it's one of the worst practices for much smaller organizations to adopt.
Honestly what I tend to see is that most enums are not exposed publicly at all besides maybe error types and configuration options (where the user usually constructs but does not match on them). In both cases #[non_exhaustive] is valid. For all of the non-public enums you get to enjoy the compiler exhaustiveness enforcement.
With #[non_exhaustive], adding a variant is not a breaking change, but only if that variant can safely be ignored. If it can't be, then it's still a breaking change, BUT you don't get a compiler error. That's a very big drawback IMO.
This makes me think of how the PNG format handles this. For context, PNG files consist of a list of chunks of different types (image data, color profile, text comment, etc). Each chunk has some flag bits that tell you whether it can be safely ignored when decoding the image, safely retained when the image data is changed, etc. That way the decoder can ignore unknown ignorable chunks and error on unknown non-ignorable ones.
If you really don’t care about compiler warnings, what’s the actual point of using Rust?
Second case is the same. The other team needs to definitely know, that their assumptions expressed in their current code are broken and need to be adjusted.
We just need to stop to take whatever shit Google is doing as the one bar to measure all others, and need to understand that they may be different requirements than a typical business. We are not Google.
I don't want to update every place someone matches on my enum, when it's something not even in my project, just to get my PR to merge. Three teams use it? Fine. Ten? More? Not fine. You are adding cases into someone else's code just to unblock your own work.
The second case is actually not the same at all. Realistically, they will just pin your dependency to an older version. Now they can't benefit from new features and security fixes without going in and adding in a new case. Massive waste of time for them.
And of course I'm not just taking whatever Google says at face value. I read their justification, and it makes total sense for anyone that works on a non-trivial project. It follows how any stable public API is supposed to be designed.
Then don't upgrade your dependency onto the other crate.
Anything more than a hobbyist will have properly pinned versions, and not just sling around version ranges loosely. At the very least will not update lock file just like that, without considering, that there may be consequences.
I just fundamentally disagree with Google on how to evolve data structures. Sloppy open-domain protobuf field presence, enum values, whatever are illusory extension points. Better to have discrete versions of a data structure --- Foo1, Foo2, Foo3, etc., and rigid checking in each one than to have just one "Foo" with optional-everything that changes implicitly over time.
It's always up to callers to decide to handle everything, or decide that additions are non-fatal and use a wildcard branch to ignore them. The same enum could need to be exhaustive for one use case, or subset matched by another.
edit: I don't know rust. in other languages he's such catch all patterns exist and you have to either capture each possible value explicitly or you express "here in this fu, I take care of these and all others I do that..."
At Google, the bottleneck is that a team changing a commonly used enum will not know how to update all the broken use sites, since it can be affecting dozens or hundreds of teams.
It is better to decouple the enum change from the use site change and let consuming teams update on their own schedule.
Note that teams generally manage their own deployments, so even a repo wide code change doesn’t force the update of an older deployed binary.
I'm working at a company with a very large Rust codebase with thousands of endpoints. We use multiple repos and each service publishes its API as crates. A few years ago those were manually written and teams used exhaustive enums frequently in their API. It did not prevent runtime issues as older clients could receive responses with new variants from newer servers. It also made versioning painful because semver would dictate a major bump, but Rust's nominal typing means that types from different major versions get different identities, making it very inconvenient to integrate with these types (think shared helper functions, extension traits, ...). This caused people to release new variants in feature bumps and wreck havoc in the dependency tree by breaking compilation of intermediate libs.
Since then we switched to code generation from an IDL for the API model. I was leading this project and decided to produce non_exhaustive enums for the Rust code: it was 2 years ago and the situation drastically improved.
We have a CI step running lints with `non_exhaustive_omitted_patterns` mentionned in an other comment. That's the right approach for such a public API. The big difference is that is that warnings are local to the crate you're working on, so they're more actionable than errors.
This was all in the context of modeling the API of a distributed system. I still tend to use non_exhaustive more often now even for regular helper libraries. It always requires some thought as you need to plan for the forward compat of your code.
If you're building one binary you can choose when to update and fix all the referents at the same time. A distributed system does not have that luxury and it makes more sense to require forward compatibility.
I guess another option is a two-phase update where you first update all the services to accept the new enum variant without ever emitting it, then you can phase in services that use it. The downside with this strategy is that you're locked into upgrades and you can't roll back individual service versions, so to be safe you probably need to delay use of the new enum variant by 2-3 releases (at some point rolling back is not a viable option and you have to publish fixes in a new release anyway).
So in a service world the only options are either "require forward compatibility" or "delay rollout of a new feature to 3 release cycles after all services in distributed system are updated" which is like a month minimum. I can see why forward compatibility is the default, and also that you might want to keep the two-phase deployment strategy for certain cases.
#[non_exhaustive]
enum Foo {
Bar,
Baz
}
fn main() {
let foo = Foo::Bar;
match foo {
Foo::Bar => (),
Foo::Baz => ()
// no `_` arm necessary here
}
}
The non_exhaustive attribute only applies to users outside of the compilation unit, because it's a tool for expressing a promise about the external API.Something I've been wanting in Typescript (and I guess it's the same thing here in Rust) is to type-check exhaustiveness of the known enum values, but also enforce that unknown values are handled. I've made utils for that but they're a bit awkward to use compared to native constructs like switch/case.
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.
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.
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!)
https://source.chromium.org/chromium/chromium/src/+/main:tes...
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.
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.
And then the ability to enforce a formalized layer between crates and the way that they assemble into your application (i.e. the public API) is powerful for comprehension and maintainability. I go as far as documenting each crate with its own README that presents it as a standalone component with usage instructions, much like an open source library, even if it's only ever used in a single system.
So a single crate has to be as small as possible so builds are fast & cachable.
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.
Everyone remembers finding some hideous name like foo.widget.widgetBuilder.widgetFactory in Java or something. It's nice to have naming rules, or at least guidelines, focused on trimming redundancy and keeping the signal high.
NO, it’s beautiful! https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris...
- this are rules created to be (kinda/mostly) uniformly applied across all projects at a Google Scale company
Having used rust at work since roughly ~1.0 days I have come to a realization:
- the style guides which work best for "blindly uniformly applied across all kind of projects/teams/people" are not the same as "my preferred style" _in a lot of ways_
- similar they are often not "the best" in every case but they are "uniformly applicable without having to make opinionated decisions" i.e. they don't cause frictions in review or when writing the code due to "style only"-decision without a clear good answer
As a more generic example. There are a lot of frameworks/style guides which lead to related logic being split across 3+ small files in different folders instead of having related code "close together". And this can be a huge pain and isn't how I would manage personal projects. BUT putting code close together will sometimes just not work for various reasons (often shared logic/cross cutting concerns) at which point you will have to make some compromise where/how to place the code which has no simple "no brain used schema-f" solution you can blindly apply no matter what. This can lead to friction. Once too many people touch the same code this tend to become a huge mess, too. So the companies use style guides which split things apart. Even through the outcome is for all the simple cases noticeable worse to work with. As it does scale to large teams, very varying skill levels and many people working on the same code.
I find it interesting that Google uses Rust. I know they work on Rust-based kernel code for Android. I'm curious to know if they also use it for networked application code, and why they picked it over Go.
Personally I prefer Rust over Go for it's types, and I never use it in big projects, so compile time does not bother me. But Google basically created Go for it's networked application code.
Nowadays, I care about their recommendations as much as the ones from microsoft, or ibm.
Still big companies, lots of smart people, but nothing above norm.
Oxide computing.
But it wasn't as coherent and reliable from project to project like this guide. Kudos to google on this one !
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.
This sparked an interesting memory for me. I was once working with a customer who was producing on-board software for a missile. In my analysis of the code, I pointed out that they had a number of problems with storage leaks. Imagine my surprise when the customers chief software engineer said "Of course it leaks". He went on to point out that they had calculated the amount of memory the application would leak in the total possible flight time for the missile and then doubled that number. They added this much additional memory to the hardware to "support" the leaks. Since the missile will explode when it hits its target or at the end of its flight, the ultimate in garbage collection is performed without programmer intervention.
https://devblogs.microsoft.com/oldnewthing/20180228-00/?p=98...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.
Other than a few examples given in the past, the Rust adoption among WinDev doesn't seem to be really taking off like in Azure.
Indeed C# is getting more low level coding features, and the unsafe memory model is being redone in .NET 11 for a reason.
Apparently outside WinUI efforts, that many don't care about, there isn't much going on, the Rust action is all on Azure side.
Rust for systems programming, C# for non-performing bound tasks (control panels, launchers, light gaming, GUI's on top of Windows CLI tools) and C++ for raw performance. And, still, I won't let any modern codec for A/V to be written in C/C++ for obvious reasons. And I am a diehard Unix+C user in the infamous N270 netbook. but dark times with automatic AI attacks are comming ahead. That's why I migrated from Mutt to Aerc, while keeping my Maildir and msmtp/isync.
At least I will be able to reencode potential harmful media for 420p/720@30FPS for the netbook in the NUC if FFMPEG (or FFMPEG based tools) were converted into Rust without hitting several vulns, because they will be everywhere:
- qemu/libvirt
- imagemagick/graphicsmagick, both the tools and libraries
- any libav* codec/parser
- libpng/libgif and similar
- zip/7z/tar/pax
- PS/PDF, of course. Especially PS, for obvious reasons.
- Some DOC/XLS formats pre DOCX are raw memory dumps and maybe they can be partially executed.
- Some other formats can act like a mini-VM bytecode too, such as RAR.
I even compiled Bubblewrap too so I can jail some of these, and yet I don't trust them 100%. Some recent exploits bypassed the chroot like nothing.
C# to me compares to Java and Kotlin (they have a large runtime or VM and implement GC).
Rust compares to C, C++, Zig or Odin (compile to native, memory is more self-managed).
There’s also work actively ongoing to make certain constructs even easier to express more ergonomically and letting user programs implement some of the magic that’s currently restricted to the standard library
If all you care about is performance, you're going to be fighting Rust's memory model for no reason.
If you actually care about performance where you'd start is with measurements. What we see so much from C++ isn't measurements it is dogma. Things C++ forces on you must dogmatically be imagined as free without measuring them, things C++ does not have get treated as expensive, again without measuring so as to justify their absence.
For example, the unstable sort in C++ (std::sort) is typically implemented in a way which introduces Undefined Behaviour if your ordering isn't coherent either because you didn't realise that was mandatory or through some minor programming error. In contrast all of Rust's unstable sort implementations have been entirely safe even in the face of such mistakes.
And your dogma might tell you OK, but the C++ sort must be faster. That's why we're doing unsafe things, it must be faster. Except, nope, slower. Slower, but unsafe. Pointlessly worse. Only acceptable because of dogmatic belief.
90% of the code I write these days is Rust. It's a great tool, and the performance/safety balance, as well as general developer experience makes it well-suited to a wide variety of applications.
But in the past I've also built an ECS implementation. For that to optimize performance (and yes I did measure this) you want to do bulk memory allocations memory, pack bytes in order to minimize cache misses, and dispatch multiple threads to read and write concurrently over your memory pool. You can do all that in Rust, and people have, but it's a pain in the ass.
And for example, if I were working on a high-frequency trading application, where every millisecond of additional latency represents millions of dollars of lost revenue, I wouldn't waste my time fighting the burrow checker just so I can have a prettier program.
Rust is an amazing tool, but that doesn't mean it's the optimal tool for every job.
Obviously like Michael Burry it is always possible that I'm wrong and I can't see why. But I did give you a specific example where the dogma says well we have to choose this unsafe way to do it, but the reality is that's not only unsafe it's also slower. It is just worse.
I am glad to hear that you measured. I've been yelling at people for not measuring for much longer than Rust has existed - if people measure and choose C++ because the numbers were better I feel a lot better about that outcome.
As to being the right tool, I firmly believe we should use a lot more niche languages which do only one narrow thing very well. One common thing you'll see argued about the Memory Safe languages is that they need runtime bounds checks and such checks are a performance cost the unsafe languages do not incur. WUFFS illustrates that if we're willing to give up generality we can have a language which is entirely safe but doesn't do runtime bounds checks - because it proved mathematically at compile time that your code has no bounds misses so such checks are needless.
Arguably for HFT in particular the dirty secret is that if things go badly enough wrong you just say "Oops" and get a do-over because money isn't real.
With that being said, I did write a compiler to specifically help me match C++ memory layouts in Rust [0], so I might be an outlier case :-)
I understand your argument as "it's easier to botch an implementation in C++ than in Rust", which is true and that is actually an argument in favour of Rust.
I strongly believe it is harder to write a C++ implementation that is sound and does not rely on UB.
The point is, there are some domains (data-oriented programming) where Rust actively resists the kind of work you need to do to solve the problem in an optimal way, and it makes sense to use a language built around the type of memory management required.
There's no point in using Rust when 90% of your work is deactivating the benefits Rust provides and working around its default behavior.
Rust will replace C++. C will we kept as a "low level ASM" similar to what inline ASM was for C.
Still, I can perfectly predict Rust based Qemu and FFMPEG's being rewritten from Bellard et all replacing the former C base. Legacy users can just use legacy machines with Hyperbola (and I'm one of them), but Rust will be almost mandatory to be protected against automatic AI attacks. Kinda like blaster/sasser but much worse. Multiplatform virii written in Golang for instance.
Servers getting poisoned media targetting ImageMagick/GM and FFMPEG on purpose, and VM's too. Thus, rustifying Qemu/Libvirt and FFMPEG will almost be a mandatory task.
Again - no one takes issue with the ease argument. The only issue was claiming that c++ somehow let you go faster. Indeed, it’s likely not the case because rust has stronger aliasing protections that let it emit more efficient code, closer to Fortran - that’s why the old math libraries you’re probably using in c++ are written in Fortran and not c++ (rust didn’t exist and Fortran enforces no aliasing whereas c++ doesn’t).
No, Rust _has_ a stable ABI, it's the C ABI. It just isn't the default.
I can confirm that this has been sufficient for all of my memory layout needs, including interfacing with existing C/C++ code in memory.
Like, I agree that C++ will be around for a long while, but the writing is on the wall.
15 years of pre LLM or post LLM ?????
There's no reason to think that current game engines will have their fundamental APIs around scene management, serialization, entity composition, and so on, ported directly to Rust, because these things are typically designed around available language features. For example, an engine written in C++ might have its own version of `dynamic_cast` and RTTI, and that's going to be an extremely awkward design in any other language.
I think 15 years is too high, but I agree that it will be a while, because a triple-A game engine is a huge investment.
Rust's type system is making it's compile times bigger than C, C++ and Zig. This does keep it away from some code that's currently C or C++.
But Rust's type system an borrow checker are not something you want to go without in Rust, while in C++ many codebases prevent the use of some features to reduce compile time right?
“Traditional” C++ looks a lot more like Java, and often like C.
Much of the compile time of both Rust and C++ comes from monomorphization and linking, both of which do a lot of work to support the zero-cost high-level abstractions favored by both languages.
> Rust’s type system and borrow checker are not significant reasons for its compile times
But isn't "hard" monomorphization a property of more complex type systems (generics, type variables, etc.)?
Ah and Rust's compiler backend dependency on LLVM and in the future GCC as well.
> Frame was created over the past month largely via Claude Code. The Assembly code in all its glory can be found on GitHub.
https://www.phoronix.com/news/Frame-X11-Server-Assembly
The eating everything part is only the usual hype cycle as folks update their CVs, in this fashion driven industry.
Except this time around AI makes language knowledge meaningless, we can vibe code anything into any language.
Naturally everyone around the globe that contributes to LLVM will gladly contribute the rewritten version as well.
Also, there's some C compiler in Rust, enough to build some crates.
I expect migrating my MUTT setup against isync/mbsync with some Golang written MUA targeting my maildir folder. I will lose some speed but I'm not at mail 24/7 in the netbook and Slashem doesn't demand a lot for gaming. Oh, and S9 Scheme and Klong for sure they work with very little, same with MupDF, sxiv for images and MPV. But, as I said, batch-mode communications will be mandatory on that device. Download, upload, disconnect. Every answer to discussion threads will be done offline.
AERC as a mail client it's written in Go and it's supports Maildir, so that's it.
Also, if someone created some SLRN fork rewritten in Go it would work in the exact same way. Slrnpull to fetch, some Go based reader pointing to the caché folder. Secure and not as slow as anyone would think.
Given how many vulns are discovered maybe even pledge/unveil under OpenBSD won't be enough. Call me crazy, but if all the OBSD people migrated to Redox OS keeping the MIT license it could be a crazy move and maybe a surreal end to the BSD Unix mythos, but it might be a much needed evolution, kinda like plan9/9front was against the old plain Unix philosphy. Evolve or die.
This kind of arguments is what gives raise to the Rust Evangelism Strike Force memes.
In some hypothetical LLM-free world where Rust is displacing C++, hiring managers will still consider C++ experience a strong signal. As is, see you at the bread lines, comrade.
Even disregarding tooling I'm actually happier writing C than (even) Odin because it's really just a natural end state of changes I'd made to how I write code over the past 7-8 years and what I expect from a language (to not do much, and to not get in the way).
It's hard to compete with the tangibles of writing/using C:
- Somehow it has shorter compile times than everything else still, particularly for release builds?
- Everything that matters (to me) has C bindings.
- All the tools just work and they work well (and a lot of them are made specifically for C anyway).
- The compilation model is actually better, more straight forward and easier to make fast than languages that try to "fix" it, unless you sit there fighting it and overcomplicate it with overwrought build systems. (`make` is better than I used to give it credit for, though).
I think Ada is the only language that could peel my attention away from C at the moment, which is ironic given my "Don't do much, get out of my way" stance. It turns out you can do more if you're sensibly designed, have the right escape hatches and actually provide real, useful features (basically every feature regarding arrays in Ada and their interplay with other features like index types, etc.). Ada is not as easy to port from Odin, though, and Ada would be a much bigger gamble than C in so many ways. We don't mind writing the code we use ourselves (we in fact prefer it), but in Ada a lot of that code would be decidedly alien to how Ada seems to work in many ways.
With that said, I do have an Ada port of a game I was working on that does illustrate a lot of upsides. It's a different possible end state.
P.S. I've tried Zig, I wrote Zig for several years before I started using Odin, it's what got me back to imperative, small, native languages. It's what started this journey back to C.
If you've sworn off actually getting any value from the programming language so much that you even went from Odin to C it feels like just writing raw assembler is a sensible choice at this point?
I haven't sworn off getting value from programming languages, I've just concluded that most languages are not useful and good enough to make me deal with the problems they have with tooling, complexity and so on over C.
Your suggestion to use assembly may be you trying to be hyperbolic, but I don't think it's nearly as hyperbolic and ridiculous as it'll sound to a lot of people. I personally think I get plenty of value out of the facilities C provides now, especially with later editions, but it may also be that it'd be holistically better to simply write assembly.
Because that's really what it comes down to: The big picture version of a lot of languages are that while the languages themselves may seem like an upgrade, their interaction with debuggers, etc., are not. A concrete example of this in Odin is that debuggers do not work particularly well with tagged unions (tagged unions have concrete integer values for tags in Odin, and the unions are generated anonymously and are not clear regarding which case is which), so whichever upside you have with language support for tagged unions, you'll still pay for it at debugging time. Meanwhile, in C with real enum types as you have in C23, your tag will be whichever enum value you have, i.e. readable and understandable, and your actual union cases will be exactly what you named them.
For just about every feature I like in Odin I have a similar story of where it falls apart with regards to tooling and other things. A "good language" doesn't mean that actually developing with it is any better than developing with an arguably less featureful and "worse" language.
I spent a considerable portion of my career writing C. But for the past few years I write only Rust in my free time (I do write little snippets in other languages, including Odin, but nothing serious)
Debugger support is like any other tooling problem, you need somebody who agrees with you about what the tools ought to do - to do the work. In C there have been decades for somebody to put together the rudimentary pieces needed to debug C and that's hardly a tall order
In the specific case you cited (tagged unions) you need a better pretty printer and you need Odin to emit the debugging info so that the debugger can understand these types and the pretty printer can display them to you. Without that you're staring at raw data and no surprise it doesn't feel like C would be less useful.
So yeah, it's not that you can't have a debugger that understands all of Odin perfectly, it's more like the reality we do have is one where basically none of them understand Odin perfectly, one has built-in (read-only) support for just slightly better Odin-specific views/functionality, two have read-only support (no interaction with built-in types because they use magic intrinsics behind the scenes and magic syntax) for Odin with custom scripts you have to load and everything else is just looking at C.
I've written Odin for 4+ years at this point, so it's not really as if this is a knee-jerk reaction to initial friction. I've spent the time and at this point I am very certain that I don't want to spend any more time with languages where tools are always bad or leaning towards bad, because I've realized that tools are really much more important to me than the languages themselves. I might even start using a language server again because C has one that's ridiculously fast in comparison to what you get with Odin, and it probably won't crash several times a day as soon as you get over some mild threshold like 25k lines, or a "whopping" 5k line file.
I don't much like Odin (Bill banned me from his Reddit because apparently I'm "just an arsehole") but in 2026 I couldn't live with C's attitude to strings. Odin's choice (using the fat pointer string slice type as the sole type for both owned strings and references into them) sucks but at least it has the fat pointer string slice type.
Why not Zig then, and C instead?
As a C/Zig outsider, I'd much rather read Zig.
Mind you, both of these languages are excellent compared to most other languages (there are a bunch of languages I've used that I'm not mentioning here because they're not even really worth comparing with), and there are certainly languages with worse tooling and overall worse outlooks for how to deal with issues. I don't want to give the impression that I dislike either Odin or Zig. They're just competing with C in this comparison, and by my estimation the holistic experience of developing in C is better than in either of them.
Anytime numbers and letters are mixed, it's more readable if the letters are lowercase. It's easier to read the variable heights - numbers are usually capital letter height, sometimes with descenders - and avoids confusing 0O, I1, even 8B and 5S (think of a degraded printed serial number, poor lighting, etc.). There's only l problem that persists.
Don't do weird crap with lifetimes to try and convince the compiler that what you're doing is ok, just throw Rc/Arc on it and be done with it.
The Rc/Arc advice also applies to C++ IMO, though you use different constructs, std::shared obviously, but there is a strong argument to be made for a std::shared_st or something which is single threaded.
It would not surprise me if this advice comes from experience with C++ where there is no Rc so reference counting is very expensive. Even so, you can greatly reduce the expense by passing things by ref where lifetimes are simple which is the vast majority of the time.
Adding Rc/Arc is just another layer of indirection and noise that makes the code hard to read.
That's pretty direct. IIRC, the Rust for Linux people also have that refrain informally
> Manual alignment
Guess, another decade before Rust robots can do columns?
"Prefer enum over bool in APIs: Use enum function parameters instead of bool in cases where the purpose of the parameter is not obvious. If you do use bool, consider using an inline comment to document the purpose of the bool in an argument list."
So.... build a linter that refuses boolean parameters, and if there's an exception, then it'll be in the comment that disables the linter for that particular parameter?
And if it's in a linter then you find out waaaaaay faster compared to rolling the dice on whether the human reviewer remembers the rule or not?
Not a professional programmer, so it's a genuine question rather than a statement.
// 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.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.
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...
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.
So it's not like I am willing to read through this and think to myself "I cannot wait to pick up some new ways of doing things". I'm the general to my agentic army now.
I guess you would code manually every now and then for your own enjoyment but at that point do you care about style guides written for scale?
I guess you would type out a comment manually every now and then for your own enjoyment, but at that point do you really care about comments at scale?
---
EDIT (above is a joke) It's very important that every time you find something that is of no use to you, you write a comment explaining that this link is of no interest to you, discouraging people from things you have no interest in. Monoculture for all!
What have you produced with your agentic army? Would you like to share with the class?
If you think style guides don't matter anymore, I encourage you to submit patches to the people on your list whose credibility you're borrowing, and see if they agree. Tell Linus to delete https://docs.kernel.org/process/coding-style.html because it doesn't matter because we have AI now. Or ask GvR if the current Python maintainers should deprecate https://peps.python.org/pep-0008/, since agents don't need it.
You tried to assert that nobody writing meaningful software has ever thought something like "hey, y'know what, that's actually kinda cool! I'm going to change my mind about LLMs being useless", which is easily false. They don't need to declare they're generals to agentic armies, they just need an open mind.
Which it seems all writers of great software do. And you don't...
We get it, Rust is great, and LLMs too. But sometimes it's like listening to teenage philosophers who just discovered atheism, who go on and on to disparage all religions every chance they get. They're so full of themselves that they don't realize they're missing entire areas of understanding about the world and people.
The juvenile arrogance on display in many threads in recent years is second-hand embarrassing. Meanwhile the greybeards continue getting the job done, with or without LLMs, in Rust, C++ or even C.
Since I'm detecting snarkiness in your words, let me clarify something important: How convincing something you read is doesn't have to match with how true it is.
I would think they're probably even more meaningful in an agentic world.
Shitty generals can't review meaningfully review the work of their troops.
On top of that all, I just enjoy programming itself. It's less and less of the meat of a software job over time, but I was coding before I got paid for it, and I'll probably keep coding well after I can get paid for it.
Except that reviewing has become just asking your agent what that piece of code does in english. Reading code has a bit of cognitive load, that we will probably drop it in coming years
How does this work for you?
Do you ask about specific functions ("what does this function do")? Then it sounds like more work than actually reading it.
Or do you ask about the whole PRs ("what does this PR implement")? Then how do you catch things like security vulnerabilities, bad design choices, unnecessary dependencies, wrong architecture, etc? Those are things that benefit the most from human understanding (nitpicking style was always the easy but unimportant part of code review)
Not about a specific function anymore, or maybe once in a while, when something looks off.
> what does this PR implement
Most of the times, the coding agent already has the summary, and asks me specific questions where it needs me.
it very rarely also happens that i catch it taking shortcuts instead of doing the "right" thing. this happens while i am taking a look at the summary of the work it just wrote.
most of the correction happens later on when i test the final output irl.
It seems to me that if the intent is not just to produce code but also to operate it, having the different pieces behave in a similar, predictable way is kind of nice. Whether the software is written by AI or humans.
> I guess you would code manually every now and then for your own enjoyment but at that point do you care about style guides written for scale?
I think they're still quite valuable in that case, for a couple reasons:
- When learning a new language (which happens much more frequently when writing code "for pleasure," as it were), "written for scale" guidelines still translate pretty well to "written for oneself" IME. At the very least, they tell you what to expect in code you read, and give you a reasonable starting point as you develop your own taste and stylistic preferences.
- I've noticed some open source projects beginning to institute anti-AI contribution guidelines, and such projects still benefit from codified style guides. Google obviously doesn't fall under this category themselves, but in other language ecosystems, their style guides tend to find use in OSS projects.
Unless you're working on your own project on which you have full control, or you have a strong authority figure in your company who cares about that, it's a lost battle.
It's sad for anyone who love their craft, but tbh I'm not even sure it matters anymore for most projects.