What Is Rust's Hole Purpose?
blog.pnkfx.org
blog.pnkfx.org
* compiles to native code with no GC or runtime overhead
* Facilities for high-level abstraction well beyond those offered by C
* Widely used in the mainstream.
That language is C++. If Rust becomes mainstream, it will be the second language in that set.
Thus, in my opinion, talking about the value proposition of Rust makes the most sense when comparing it to C++. I find it much easier to write and understand Rust than modern C++, and that’s what makes it valuable, for me.
That saves me time and energy - time because I don't have to wait for my misunderstanding to manifest weeks or months later at runtime (in a worst case) and energy because my editor will fill show me signature information inline - I can just glance up a few lines if I need to remind myself of what the constraints of a variable are.
I know for a fact that I don't strictly need this - I am capable of writing C that preserves those contracts, at least for smallish projects. It just takes much more time and effort. And in big projects even the "gods" have trouble with getting it right every time.
In fact, I've been willing to tackle much more difficult problems professionally that I would have shied away from (outside a research setting anyway) without the guarantees rust tooling provides.
The whole "safety is a gimmick" angle always brings to mind a bunch of 9-fingered carpenters sitting around trying to convince their boss not to buy saw-stop because you just gotta be careful using the tablesaw.
You could do this with basically any language advancement. Ignoring classes, C++ was (mostly) what C... Ignoring GC, Java was (mostly) what C++...
Also, a language is more than the sum of its parts. If it weren't, kitchen sink languages would be the best ones out there, because they have the most parts.
"And the sanitation"
"Oh, yeah, the sanitation, Reg. Remember what the city used to be like?"
I know some larger corporations use it but I don't hear much about it otherwise. The most obvious plus side I hear about is the small memory footprint and fast boot time which makes it good for functions-as-a-service.
It is also getting generics know which makes it sound like the simplicity was a lie or will be a lie.
I'm sure many will say "well I could have told them they were necessary from the start", but the overwhelming majority of these people are just lucky--they picked a conclusion that happened to pan out. And we know this with certainty because most of these people make arguments for generics where they are neither necessary nor useful--they're merely familiar with languages with generics and they reach for them on first sight of a problem. These people also can't articulate the advantages of not having generics--namely the unreasonable productivity that accompanies everyone writing the same code absent personal flourishes. The very fact that these people consider it a no-brainer that generics were the way to go from the start betrays their error--generics are only just worth their costs, and the emphatically pro-generics camp can only rarely articulate those costs due to their inexperience with other kinds of programming.
The value of generics is obvious if you ever write your own container. Go had pre-Java-1.4 level type safety for any container not specially blessed by the creators. Prior art on how to do them without significant compile time cost was already established by Java, not even some obscure academic language. Go was dumb from the start.
You betrayed your own credibility. As previously mentioned, those who can't articulate the tradeoffs associated with the generics question lack qualifications--they are amateurs, and their opinions aren't interesting to professionals. Consequently, for lack of interest, I'll leave you to your opinions.
I've been hugely interested in this recently, at least part of what you are describing is programming language affordances.
Imagine you have some C that has (for whatever reason) named two important functions "class" and "fn" which are completely reasonable C symbol names. In C++ that word "class" is reserved, so you can't name symbols class, but, that is what the C symbol's name is so too bad? However in Rust, even though fn is a reserved word there's no problem referring to that symbol, you just have to spell it r#fn meaning "the symbol named fn" as distinct from the keyword fn.
Edit: MLKit was the ML dialect I was thinking of - looked it up
More important is tracking the owner, which perl6 used.
Safety is a gimmick?
In C++98 (the first ISO standard version of C++) you can fairly easily organize a program such that any low-level activities are confined to classes that are almost impervious to misuse by the rest of the application, so there will be no memory misuse or leaks, or out of bounds arithmetic.
If Rust takes off, there will be widespread use of its unsafe parts by programmers who are under pressure to deliver something and take the obvious route of telling the machine where to put what bits, exactly like what C++ programmers have been doing.
Also Rust is pretty mainstream at this point.
* Discord replaced Go with Rust[0]
* Microsoft's VS Code uses ripgrep for searching through code which is coded in Rust.
* npm is using Rust
* Cloudflare (I believe for their serverless platform)
* Figma (unsure how)
* And I'm sure countless more, hell one of my former employers is using it for mission critical work in place of C++
As you can see Rust is used by some pretty massive services, even if you don't use them, millions of people do. In fact VS Code is the most surprising to me I had no idea it was using it all along. I also believe Atom was looking into using Rust to improve performance for Atom but I'm not sure if it was just native code in place of JS / HTML.
I would argue Rust has entered the mainstream, it will be slow to be far more common, but it is getting there. I will not be surprised if we see it all snowball once there is a full feature web framework like Django or Rails but for Rust with all the batteries included. Go took a little while before it became as big as it did, and some would naively argue Go isn't mainstream, while they deploy code using docker to their kubernetes cluster (for those who missed it both of those tools are coded in Go) or what have you.
[0]: https://discord.com/blog/why-discord-is-switching-from-go-to...
* A build system
* A package manager with powerful features
* A toolchain manager for getting different version of compiler etc
* Code generation in the language
* Build scripts in the language
* A test framework
And when I write "a test framework" or "a package manager", it's not just that it has one, but that it has one.
On the mainstream question, since I told friends and colleagues I'm learning Rust, I get a lot of statements like "I think I should learn that too, it looks like its going to take off". That is a strong signal that it has already taken off. Like once regular investors have heard of some stock (or bitcoin).
I have many colleagues who have foresworn C++ but are liking Rust (myself included).
The author talks about drills and holes, but to me, the conversation is more analogous to cordless drills versus regular electric drills - they both can do the same thing, but have different characteristics about the process of drilling the holes.
The Rust community considers safety violations to be the language's fault not the implementer’s fault. In C++ if you violate the language spec then you’re and idiot who just blew their foot off. In Rust the people responsible for the project take it upon themselves to make sure that nobody blows their foot off. If you happen to cause UB in safe code, the community says “oops yeah we messed up how do we fix that”. This is a huge difference and the article alludes to it but I don't think the author states it clearly enough.
Rust’s “hole problem” is that it forces developers to write safe code (conform to the language spec) up front which ultimately saves time and money. Developers are the audience and they want the best tools. Users want a hole (often as a means to an end, sure) and don’t care how it gets there; developers who make holes all day want the hole in the wall and not in their foot as frequently as possible.
In my experience the added safety guarantees have made me more comfortable in "going faster" and back to vehicular terms the choice is still there to not fasten the seatbelt and go `unsafe`.
I think miri is a part of the answer to this, but it is not perfect. At the end of the day, you need unsafe at some level to do anything useful, and we need more explicit rules about how to do it properly.
Speaking personally, Rust offers a rather nice featureful syntax (and libraries), and saves me the trouble of worrying about certain kinds of very typical mistakes.
I may want a hole, but a cordless drill with a comfortable hand grip is very likely my tool of choice. Especially thinking back to my father's corded underpowered temperamental drill with the easy to lose chuck key...
It spent an awful lot of time on that without making very good points.
About one paragraph of text could have pointed that reducing the surface area of unsafe code is therefore a good thing, which leads to "rewrite it in rust" which gets you more safe code.
There also seemed to be a little bit of conflation of safe code with bug-free code which just isn't possible. Arguing English semantics of words which are being used to describe very specific compiler behavior is going to be a GIGO argument.
I worked on Google Earth for a few years, and the core was in C++. With ASan and modern C++, memory safety bugs rarely slipped into production... perhaps once every 3-4 months, and this was a million line codebase with 20 engineers working on it.
When you consider the cost of a memory safety bug (some users get odd behavior), how rare they happen (because of our good test coverage), and that everything's sandboxed in WASM anyway, there's just not much cost to this kind of memory unsafety bug... and certainly not as much cost as a full rewrite.
RIIR makes sense for projects whose memory unsafety causes catastrophic failure. And even then, in some of those cases it makes more sense to use Java or Javascript, which don't expose unsafe operations.
RIIR makes sense if someone's doing something with extreme performance requirements, and they're okay with a tiny risk of memory unsafety (from unsafe code).
All just my opinion though, I'm sure there are many other great opinions out there.
But man, after trying to watch after a C++ project with other kinds of programmers on it I kind of wish it was built into the compiler. Rust is pretty much what I do by convention.
Also when a beginner asks me whether they should start learning C++, prepare for a long uncomfortable silence while I look for the right words.
In an actual business, one has to justify a project's existence, by showing growth, new features, new users. Imagine stopping that while we rewrite a million line codebase. Now imagine a project which doesn't bring in revenue, and just delivers social good, while having out-of-touch executives looking at our resources and headcount like hungry vultures.
Rewriting in Rust would have cost us years, and would have killed Google Earth.
It's not something that has to be done wholesale, obviously. Language interop between Rust and C++ is constantly improving, with one goal being to make rewrites happen gradually while keeping the same interface wrt. outside C++ components.
The boundary between C++ and Rust code is often a lot trickier than one might think, because one has to reconcile conflicts between C++ paradigms and Rust paradigms... when one considers all of the temporary code that reconciles those conflicts, we see that the cost just went up.
And then moving that boundary is tricky to do in a healthy way, especially when using proper A/B testing practices which require us to have both the old and the new code alive in the same binary.
Rewriting often sounds like the solution to things, but in practice it's a very risky and costly thing to do. See also: https://www.joelonsoftware.com/2000/04/06/things-you-should-...
What am I missing?
That's across Java, Go, C#, Python. Maybe there's a GC language I should be using where all this feels easier, but if so I don't know what it is.
Having to create borrow checker friendly data structures doesn't bring anything to the table when writing GUI applications (including design tooling), distributed applications (Akka, Orleans, Erlang style, RDMS SP), CLI tooling, compiler tooling....
In what concerns languages with automatic memory management and support for value types, my list is somehow different, D, Nim, C#, F#, Swift, Go, Linear Haskell, Ocaml with Effects, Eiffel, Common Lisp.
And I leave Herb's talk regarding those issues with RC types,
"CppCon 2016: Herb Sutter “Leak-Freedom in C++... By Default.”
Even the first chunk of Herb's talk, before you get to reference counting - illustrates why you might feel more comfortable in another language compared to C++, as once again C++ has the wrong defaults. Rust's defaults are better.
Nullable shouldn't be the default. It's really hard to undo this bad decision, it's not one of the easy ones where I think C++ realistically could (but still won't) just fix it, but it's still a mistake. By getting this wrong C++ adds an unnecessary burden.
Since Rust doesn't get this wrong that burden isn't present. I am never worrying that the Box<Thing> in a Rust structure might not be there, by definition it's a Thing in a Box, if it might not be there that would be written Option<Box<Thing>> and the compiler would let me know if I ever forgot to account for the None case.
And it keeps happening. Later Herb wants an array of known-at-runtime size on the heap, so, he makes one with unique_ptr but of course by default C++ doesn't remember how big this is, so he needs to make sure he tracks it separately, more anxiety. Rust can Vec::into_boxed_slice() and the resulting slice automatically remembers how big it is, even though you've given up the vector's ability to grow or shrink. The machine representation ends up the same if you do it right in both languages, but C++ gives the programmer another thing to worry about.
Even Google isn't comfortable into pushing Rust into app developers for their OSes, despite the amount of adoption at kernel and driver.
So when Android comes out with Rust Compose, Fuchsia does Rustter, or Native Cloud folks migrate in mass to Rust, then I might eat my hat.
Naturally you might refer to Rust/WinRT, whose tooling is a joke versus C++/WinRT, let alone using .NET alongside Blend and VS.
Doable sure, then again there are people that also insist into using COM from C, regardless of how sane that might look like in practice.
So unless Rust reaches a state where ownership is transparent to app developers and distributed computing stacks, we will keep on disagreeing.
When things get more complicated sure, Rust can mean you spend too much time figuring out how lifetimes should best work compared to a GC environment. But even a fancy GC doesn't promise to release unused resources promptly, so for non-memory resources you can end up needing to care about lifetimes anyway, and the GC languages do not prioritise this problem.
FWIW the phrase you probably wanted is "en masse" from the French meaning "as a body" not in mass.
Exactly to make the point that those languages offer the same deterministic tooling and not mix with how Java does it.
I don't see that as any kind of upside over Rust. It sounds like one of those "my first Rust project" codebases full of Arc<Thing> when Box<Thing>, Thing or sometimes even just &Thing would have been appropriate.
In fact this then makes me realise you consider "it has reference counted smart pointers" to be "automatic memory management" but then you say Rust is suited for situations where that isn't possible, does that mean you didn't know Rust has reference counted smart pointers (two kinds even)? Or does it mean you consider all of Rust above core to be superfluous (Rc is in alloc) ? Either way this makes very little sense.
And so I went back and now I'm also puzzling what you think Value Types are and why you believe that's relevant. Is the problem that you bumped your head and now you think Rust is Java ?
The modern trend is closer to refactoring C++ code so that it's more Rust-like, not the other way around. The C++ Core Guidelines include plenty of indications on "paradigms" and overall design, so this is something C++ developers are being asked to do anyway. But unlike these, Rust is fully intended to ensure no unsafety in the safe subset.
There are a lot of patterns in modern C++ which the borrow checker rejects, for example the observer pattern and dependency injection (the pattern, not the frameworks), which are often the best tool for the situation.
Also, are you saying that the C++ Core Guidelines encourage us to make code more Rust-like? I would love to read up on that, if you have a source.
I don't see any occurrences of "Rust" in this document...
Better like this?
I also assume they meant that that we should adhere to AxM in C++ (since that's the only thing new Rust brings), to make interop with Rust easier, but I could be interpreting incorrectly.
Could you say what they are?
Presumably, without the potential for memory-safety bugs, there'd be no need for anything like a WASM sandbox, no?
If so, then can't the costs of the WASM sandbox (overhead, potential exploits in the JS/WASM runtime, etc.) be tallied under the column of "costs of memory-safety bugs"?
In about the same sense that e.g. the costs associated with running a Web Application Firewall in front of a Wordpress instance, can be blamed on how vulnerable/exploitable Wordpress+PHP are as a stack.
If you avoid introducing an attack-surface in the first place, then you don't need to spend effort on guarding it.
In the context of a web browser, the browser JS execution-context is itself already a sandbox, so running WASM there isn't necessarily doing any sandboxing per se (although it can); it's more just serving as the current state-of-the-art way to host arbitrary native code in the browser. (Too bad about PPAPI.) You'd still be using WASM here whether there was any sandboxing benefit or not.
I was instead more thinking about the Google Earth "native" desktop + mobile apps. Those are the environments I presumed you meant when you said that Google Earth is "sandboxed by WASM." Those deploy environments are where adding an intentional sandbox layer would get you some additional safety, over just having the user run a "raw" native C++ executable on their device.
We didn't rewrite iOS/Android either, any memory unsafety bugs just cause odd behavior on that user's device, and wouldn't e.g. give an attacker root access to our servers. The costs of the occasional memory unsafety bug didn't seem to approach the cost of a rewrite.
I should say, rewriting servers (especially public-facing ones) in a memory-safe language like Rust or Java is a much more reasonable proposition, but for client code, it's a slightly different story.
Rewriting C code in Rust is probably quite economical.
The value proposition of Rust is to make it easier to solve deeper problems by combining a state-of-the-art language (that will be designed to get out of the way as much as possible) with the best efficiency.
> tons of tangled and non-generalizable business logic
This can often be made more maintainable by using embedded DSLs. Rust includes language support for macros that makes it easier to design and use special-case custom languages.
I don't think the other nice properties of Rust can explain why it's going viral when so many other fast native languages in the C family haven't. Libraries being sound internally doesn't cause a network effect, but soundness at the interfaces between libraries does. The rust ecosystem goes extremely deep in transitive dependencies, and it's not just a tree; you have many libraries that get used by many other libraries, like serde, rayon, anyhow,... and it all still manages to compile and work together almost every single time you pull some random rust project off github. You can serialize almost anything in Rust because your library authors probably include serde support for their types... because ~their dependencies did. In C++ authors are more likely to be afraid to take on an additional dependency, and roll their own little serialization thing that only works within their library. I've seen the rust ecosystem getting locked into one widespread serialization library discussed as a problem, but it's a lot better than having zero widespread serialization libraries.
Rust had the best language features for this and the most momentum behind it with things like wgpu and bevy. Fighting with the borrow checker and unsafe Rust is not something I do all day or every day, it is just something you live with.
> At this point, while reflecting on that topic, I decided to look more into the origins of the drill/hole adage; that diversion led me to a lovely post critiquing the adage, saying it “doesn’t go far enough.” The heart of the argument there is that people don’t want holes either. [... ]
but then TFA didn't actually go there for Rust. After laying out a great example of how the purpose of a hole is ultimately about time (and possibly frustration), the author fails to reach a similar end-goal for Rust, despite hinting at it:
> But, thinking of the drill/hole adage, I stopped and asked myself: “Who wants safety? Is it an end in itself? If it is merely a means to an end, then to what end?”
What is the true end-goal? Saving lives/money/property by avoiding errors?
> Can I just say “Rust developers spend less time debating about who is responsible when issues arise, and they spend less time figuring out how to get a performant solution into shape”?
The author sneaks in the assertion that issue attribution is the primary cost of issue resolution. I don't think this is true at all. What about actually writing & testing the patch?
If Rust has a technical approach to solving issues, then Go has a social approach. The latter is so darn simple that an intermediate Gopher can grok a codebase and contribute patches relatively quickly. Go is easy to hack; it's C with garbage collection and concurrency primitives (and an excellent ecosystem). That's why it was made!
I think Rust's primary value proposition is expressiveness. People enjoy writing Rust, because they can represent complex ideas with few LOC. Safety is a distant second. It's a language for enthusiasts, not products.
If you want language where safety is truly #1, well, Ada is going on half a century of usage in safety-critical systems including aerospace.
Simple constructs such as sum types do not exist in Go. How do you express that a value is either type A or type B in Golang? Go, in its infinite simplicity, does not allow for that, instead it allows you to express that a value can be type A or type B, type A and type B, or neither! Simple right!
And then errors! Go takes the simple approach with regards to incorrect code in that it just does not care if your code handles all possible error states or not! Simple, just don't give a shit!
If your career is in software and your decision making process for a programming language is "what can I learn in an hour?" then your decision making abilities are questionable.
I posit Rust has a poor return on investment. If you're going to spend time learning a new language then make it a language that completely changes how you think about programming: something like Clojure, Scheme or Haskell. Even if you never create a single system using these languages you will be a better programmer for having learned them. I'm not so sure the same can be said for Rust.
Frankly, outside of subjective error handling preferences, I don't see much value in sum types. They encourage building towers of type abstractions and obscure what is happening on the wire.
They obscure nothing, sum types in rust have 0 overhead. You cannot in go faith argue that Go gives a more accurate representation of what occurs "on the wire" than Rust.
> Rust offers a higher variety of tools to define modularity boundaries.
"Higher variety" is among the last things I want when trying to understand a big new codebase.
Can you expand on this? I actually lean towards the same belief but wants to hear your reasons.
Can any gophers suggest one or more exemplars of simple big codebases for us to test our beliefs on?
What nonsense. Companies across the board are adopting Rust not because it has some hype behind it, but because it solves real problems, like memory safety and performance.
I can't imagine a serious blog post in 2022 questioning the purpose of Go because it is evident in the large amount of enterprise software being written in it.
Go 1.0 was released in 2012 and the language has barely gained any highly impactful features since then (generics aside, which are quite new still). Rust 1.0 was not out before 2015 and the 2018 edition already introduced huge changes, with more in the pipeline even today. It hardly seems sensible to describe them as being in the "same generation".
C: 1972
Go first (real) commit = 2008
Rust first (real) commit = 2010
Versioning schemes are incomparable. The two langs are from the same generation, period. To suggest otherwise requires mental gymnastics.
And yet so much (not all, but a substantial part) of what that book is about has very little relationship to language safety. Rust will not protect you if there's a backdoor left in the system. Rust will not protect you if there's no password, or absurdly weak passwords. Rust will not protect you if your entire system design is predicated on a perimeter defense with no internal checks. Etc. etc.
Now, I'm not so stupid as to believe that we shouldn't do all we can, and that can include language safety. But by itself, that doesn't have a lot to do with the huge end goal laid out in the book, which might be summarized as: be able to build computational systems and networks that are extremely resistant to unintended access, utilization and modification in pursuance of personal, political or national goals".
Yes, yes. I know that.
But we literally have a book floating around around THE END of the WORLD and us nerds can't justify even the first step around fixing these systems. It's like someone asking what good fire hydrants are since they won't help with battery fires.
If you have one team of 10 people write a browser engine in C++ and another team of 10 people write the same browser engine in safe Rust (or as much safe rust as you can get away with), over a 5 year timespan you'll discover fewer UAF bugs in the Rust-written engine than the C++ one.
This is the value prop for any company deciding to use Rust. Obviously every language comes with tradeoffs, but this is concretely what people mean when they throw around the word "safety".
The author is also totally correct in pointing out how easy it is to include unsafe Rust in your code by linking unsafe crates. I think this should definitely be an area of discussion and awareness-raising on the part of developers.
Has it ever been shown that it’s possible to write a full browser engine in Rust? I believe for C++ it has been proven multiple times. If I am not mistaken, Servo hasn’t been finished in 10 years.
Mozilla laid off all their servo developers in 2020
> Has it ever been shown that it’s possible to write a full browser engine in Rust?
Why wouldn't it be possible?
Yeah, I know, that’s sad.
> Why wouldn't it be possible?
I don’t know if it’s possible in reality or not, but if I have to, I can imagine some reasons (I’m making them up): maybe it takes too long to write proper safe Rust, or maybe developers get stuck bikeshedding over use of language features, or maybe the language’s learning curve is too steep, or maybe compilation is too long for fast dev iterations, or maybe developers who like Rust don’t like large codebases, or maybe Rust does not provide any tangible benefits over already existing code, or any combination of reasons.
Of course, you can write any program in any general-purpose language, just not everything is practical to be ever made. Like, I doubt people will make a full browser engine in Python, although it’s possible in theory.
So no, I guess they didn't bring an entire re-write to market in that time, but I don't think you can attribute any of those failings to language choice.
All your listed reasons apply equally (or even more strongly) to C++.
It is. There is an unofficial `cargo geiger` tool that will alert you to these issues.
Coincidentally, we're working on these problems with Vale [0] by obviating the need for unsafe, while still having single ownership's performance benefits, by taking generational indices (a common Rust/C++ technique) and building them into the language itself, and by moving borrow checking to the region level instead of the object level [1].
Time will tell if it works out!
[1] https://verdagon.dev/blog/seamless-fearless-structured-concu...
Many things in software actually play this role, from obvious thing like unit tests through to using popular software (if it works for everyone else then it's probably your bug). If no one else uses your exact Chipset/OS/language/compiler/library (version) matrix then the bug could be anywhere.
I'm not sure it has an official academic name though. Modularity? Re-usability? Safety? Reliability? Predictability? Repeatability? Good ecosystem? There's a few things that overlap and combine.
Not sure that is the Unix philosophy but definitely the attitude of many 90s C programmers. But also we want power and safety at the same time. A smart matter drill, if you will, that will dissolve when it hits flesh. Rust currently ushers a lot of thought about safety into the coding process, while with C you can start dangerously and then fix later with Valgrind/Purify etc. fun but bad results for OpenSSL or sudo or parsers in general.
And on safety, what I really want is a sawstop. I'm super super careful, but uh. I really really really don't want to lose my fingers and have them sewn back on. Safety is a really good quality to have, even if it's not idiot proof, even if I can lose my fingers in so many other ways with so many other tools. I want that little bit more, anything just about to not end up in the E.R.
True, but this is inherent to deterministic deallocation. Rust is getting local allocator support to make it easier to manage these tradeoffs. (Local allocators are commonly used already in C/C++.)
Local allocators are also a thing in many languages with automatic memory management.
If Rust can avoid more errors with nearly the same performance profile (and control) offered by C, it's an improvement. The Hole purpose is to be a better low level language.
There's a library for doing full X.509 certificate parsing and verification: https://briansmith.org/rustdoc/webpki/
There's definitely some attempts at doing pure-Rust SSL, but I suspect a lot of them are also doing some sketchy things with crypto that shouldn't be trusted (getting constant-time stuff implemented properly is really challenging, and probably requires large amounts of assembly to guarantee correctness).
A restaurant customer doesn't care what knife the chef used. But chefs still choose to get different specialized knifes for different tasks.
Hm, interesting that this boils down to a wholly unsupported claim.
Part of it isn't even coherent to me. In my experience arguing linguistic minutia has nothing to do with programming languages (or any specific domain) and everything to do with personalities and social interactions.
As for spending less time wrestling with the language environment, I suppose that very well may be true. But it may very well not be true. Here it's an assertion without anything backing it up. It certainly seems possible to me that another safe language (e.g., Javascript) may win in this area.
Never heard that one before, will remember! Any more such phrases?
However I can see how people coming from C might consider the for loop the more natural approach.
This doesn't translate to much of anything in the world outside of Rust, and it boggles my mind that so many HN comments use it as a mere buzz word, thus devaluing it.