Hacker News new | ask | show | jobs
by ziandrome22 945 days ago
I remain unconvinced about the viability of Rust for many kinds of systems programming. I'm not sure how I feel about it in the Linux kernel, although I suppose it doesn't matter since it's likely to not penetrate very deeply so to speak.

If there are any Rust experts around...what am I missing? The way I see it, Rust is still fundamentally designed to work at a higher level of abstraction than C, and is still mostly dependent on C (even C++ really, due to LLVM/Clang). And bare metal or "first compiler" support for bare metal doesn't seem like it's really intended to be a first class use case. At least that's my impression of the ecosystem from the little time I've had to play around with it.

Is this mostly just a thing to get more young people interested in kernel development...allowing them to start out in less important areas and in a language they are passionate about? Or is this a serious proposal about the future of operating systems and other low level infrastructure code? Do you just program everything in unsafe mode? What about runtimes?

It seems to me that Rust isn't even really intended to compete with C for the use cases in which C is dominant in 2023. Every indication is that for "serious Rust in production programming" it's mostly a C++ crowd. Whereas for myself and most of the C programmers I know, Zig has sort of filled that similar space and seems to take the concerns of C programmers more seriously and the team has an attitude more in line with the C culture than the Rust team does. I could spend hours writing examples of this but it's even apparent in the way the Zig team has handled its relationship with LLVM, where they seem very serious about trying to not accept it as fundamental to their language and eventually even eliminate the dependency on the C++ code...with Rust it doesn't seem like this is even on the minds of most of the users. It's purely a dependency for them and that isn't seen as being fundamentally at odds with the intended use cases. That is totally okay...but it ain't the C culture if we are to accept that such a thing exists.

18 comments

I think you have misunderstood rust.

Rust is not fundamentally designed to work at a higher level of abstraction than C. Rust is designed to work at a range of abstraction levels, from as low as the lowest level C code to something fairly high (but still short of a language like python). Rust is designed to make it easy to quickly build abstractions on top of super low level (rust) code, because usually that's the less error prone way to do things - that doesn't prevent it from working at those levels though, and if anything it makes working on systems where you have to work on super low level code much easier to use.

When working with low level rust you don't "program everything in unsafe mode", you program a few really low level bits in unsafe rust, but quickly make abstractions that allow you to avoid making the vast majority of your code unsafe. This is opposed to languages like C/C++/zig/... where there isn't anything but "unsafe".

Rust doesn't really have a runtime by default (beyond libc for non-baremetal code).

There are a few tiny niches where rust isn't designed to compete with C, but they really are tiny niches. For example where chars aren't 8 bits.

I'm honestly just not following what you're saying about C++. Rust code tends not to depend on C++ code apart from maybe some system libraries that everyone depends on. The rust community tends to be overly-keen on rewriting those libraries in rust, not underly-keen. Obviously some people will make code that manages to depend on the language - but rust doesn't make it easy (like zig does...).

As for the relationship with llvm - rust doesn't actually have a hard dependency on it anymore (with support for a compiler backend called cranelift, written in rust). I also just don't see "the compiler depends on another language" as a huge impediment - as others have mentioned C compilers tend to as well...

> Is this mostly just a thing to get more young people interested in kernel development...allowing them to start out in less important areas and in a language they are passionate about?

Not likely. At the moment you need to do extra work to get Rust working well. It's not exactly beginner friendly and doing work in the kernel, you'll need to dig into C anyway.

> Or is this a serious proposal about the future of operating systems and other low level infrastructure code?

Serious code already exists, so... Yes?

> Do you just program everything in unsafe mode? What about runtimes?

Why would you? You need that only when interfacing with something that can't hold the Rust compiler assumptions. See for example https://github.com/AsahiLinux/linux/blob/gpu/rebase-6.4/driv...

The few places that need direct access / unsafe are almost all single-line areas with an explanation.

> but it ain't the C culture if we are to accept that such a thing exists.

I don't get that whole part of what you wrote. What seems to be the culture / why does it matter in the technical sense? Some parts of the compiler are written in C++ - what's the specific issue here?

Having a memory safe language in the kernel is very serious. More and more C programmers I speak to say they realise with Rust they will likely never work with C again full time.

Yes Rust helps bring in the next generation of Linux devs. It needs to to survive. But it's not because young people like Rust, it's because C developers like rust too.

Yes, Rust has unsafe and unsafe rust is trickier to get right, but you use it opt in and it's only a small amount if the code. Zig is still having unsoundness bugs in relatively simple code

> More and more C programmers I speak to say they realise with Rust they will likely never work with C again full time.

Speaking as someone going the other way, just started working with C full time.

Yes. Oh Dog, Yes!

Data structures that rely on the memory layout semantics of the C compiler and casting void * is very cool, very 1990s, and does my head in!

I don't have much experience and I see C as something I would never be able to touch as they seem quite high level for me with the manipulation of memory and stuff.

And from what I see, Rust can sort of make it easier by making you think about the lifetime of the memory while coding and that's why I really wanted to learn Rust

"Not having C++ anywhere in the stack" is not a goal of the C language or any major implementation I know of. The two major OSS C compilers, GCC and Clang, are both C++ codebases.
I tend to agree with your view.

I attempted to port a low latency trading system from C to Rust last year, but ended up abandoning after 6 month of development.

The overall feeling that I got is that Rust made my life a dream for 80% of the codebase, the _non critical, non high performance part_.

There are tons of well written libraries, cargo is awesome, the performance is on par with what C++ would do, etc.

But the last 20% of the code base, the high performance part, was a nightmare to implement. The Rust static safety basically get in your way constantly for any kind of non obvious memory layout (self reference, etc). Dynamic safety (cells, Rcs, etc) just add too many overhead for the the critical path, and the "escape hatch" of "unsafe {}" ended up being 1000x more error prone that C.

I keep some resentment against the Rust community from this experience to be honest. I felt like instead of understanding the constraints & limitations of a fixed, microsecond time budget that I had, and trying to find solutions and be open about possible improvements, the overall trend was more in trying to defend Rust with whatever it takes.

At the risk of sounding like I’m trying to “defend Rust with whatever it takes”, your argument seems bizarre to me.

Even at the surface, if your desired solution is so antithetical to the type of structure that Rust tries to push you towards, you can quite literally just write this component of your code as if it was C. Just using pointers instead of borrows and tag all your functions as unsafe and… pretend you’re writing C? At that point you’ve, I think, more or less disabled 95%+ of the bits that would prohibit you from writing code exactly as you would in C. You don’t get the benefits of Rust for that part, but at least you get them for the remaining 80%.

Or you can very literally just write the “hard part” in C and call it from Rust. You might have to make sure you can’t panic across language boundaries, but other than that the C interop is just about the best I’ve seen from any language.

I also don’t entirely understand how unsafe can be 1,000x more (or even 1.5x more) error prone than C. But I’d love to hear how. The only “trick” to unsafe is that you should aim for your unsafe blocks to be “unit-safe”. Meaning they might do something unsafe inside, but from the outside looking at it as a black box, the unit functionality of it should be safe. I don’t think the docs do a good enough job here of encouraging that style of design. You can violate this guideline, but doing so without sufficient care is quite likely to result in bugs. But of course if you did the same approach in C, you’d have a similar outcome.

The only real way I can reconcile your points is if the performance-critical bits that seriously impact the design of your program are scattered uniformly and don’t have anything resembling clean boundaries. I suppose that’s a real possibility but it does seem very foreign to me.

Yeah see, that is what I thought at first as well.

I sort of imagined that I could get the best of both world, and just "unsafe { <C style code> }" my way out for performance critical things.

But the thing is, the static safety boundaries of Rust allow the compiler to make much, much tighter assumptions than C & C++, especially around aliasing rules, un initialized memory, and moves.

When you relax these boundaries with "unsafe {}", you don't enter "C world", you enter the litteral gates of hell where any innocent temporary cast can throw you in a random load/store reordering bug.

Do you mean innocent temporary cast from a pointer to a reference? Cause yeah, those aren't innocent. And that's a newer realization and there were serious documentation issues around it.
Thanks for the reply. I think if you combine unsafe with raw pointers instead of borrows you relax the rules enough to avoid this. But in this specific corner of things, I haven’t had direct experience so you may very well be right.

There are still some Rust-specific details you would still need to handle—as you mentioned, uninitialized memory—but for that one specifically I haven’t found MaybeUninit to be particularly cumbersome.

> Dynamic safety (cells, Rcs, etc) just add too many overhead for the the critical path

A low latency trading system can't have Rc, or any C equivalent of it, in the critical path, because it does allocation. More generally, your story doesn't ring true to me, because the performance-critical parts of a low latency trading system have to be so simple that there isn't scope for any of the tricky bits you talk about, they have to be braindead simple loops over simple data structures.

One of my colleagues wrote a low latency trading system in Rust. He had to learn Rust to do it, already knew C, and today thinks this was the right decision.

> your story doesn't ring true to me, because the performance-critical parts of a low latency trading system have to be so simple

Hu, so it doesn't ring true because... you feel like it's too complicated from what you imagined? That's a first.

> that there isn't scope for any of the tricky bits you talk about, they have to be braindead simple loops over simple data structures

That is far from the reality of low latency trading systems. Let's just look at the very first building blocks:

1) You will need some form of userspace packet polling, along with its associated multicast A/B line arbitration. That alone is not "simple braindead loops", and we're just talking about getting 1 UDP datagram here.

2) You will need some form of packet queueing before decoding, so that you do not drop packets under bursts. That most likely means some variant of lock free ring buffer in shared memory. Far from "a bunch of brain dead loops" as well.

3) You will need to decode packets and maintain an order book state. That mostly implies a purpose built b+tree. If you've implemented any of those, you will know it's also far from simple.

4) You will have to compute some indicators based on order book state, which most likely will lead you to some form of linear algebra.

5) You will need to disseminate such indicators to perform some simple close formula variant of portfolio optimization. More linear algebra.

6) etc.

I'm happy your colleague that he managed to do all that without struggling, that was not my experience, that's all. But to say that it's "just braindead loops over simple datastructures" is either a sign he didn't do a _real_ low latency system, or he just was somehow spared from the real underlying complexity.

This is a common thing to say for folks who are really good at low level C/C++. You guys know too much, seen horrors no one should have ever seen and came out alive on the other side.

The problem is, the things you needed to do to stay alive in this environment are antipatterns in Rust and you’ve learned the hard way Rust actively opposes being fed Rust antipatterns.

Self referential data structures are some of the hardest problems in CS to get right. There are patterns that work with Rust which replace pointers with eg generational indexes. You’ll find people do the same thing in C++ once they get burnt one time too many. I think you’d have a very different experience if you approached your system with an ECS framework, either off the shelf or roll your own.

> and the "escape hatch" of "unsafe {}" ended up being 1000x more error prone that C.

IMO this is the biggest issue right now. `unsafe` needs some refinement, certainly.

> the overall trend was more in trying to defend Rust with whatever it takes.

This can sometimes be the case, unfortunately. But fwiw I think a lot of us in the community agree entirely that there's room to improve in the unsafe world.

> is still mostly dependent on C (even C++ really, due to LLVM/Clang)

I'm not following the assertion that compilation with LLVM/Clang introduces a C++ dependency on the language being compiled (Rust here).

This comment confuses me.

> In August 2012, the GCC steering committee announced that GCC now uses C++ as its implementation language.[57] This means that to build GCC from sources, a C++ compiler is required that understands ISO/IEC C++03 standard. > On May 18, 2020, GCC moved away from ISO/IEC C++03 standard to ISO/IEC C++11 standard (i.e. needed to compile, bootstrap, the compiler itself; by default it however compiles later versions of C++).[58]

So for the past >10 years, gcc and clang have both had a C++ dependency. What is unique about LLVM/Clang here?

If I understand what you’re considering, it’s that the compiler itself may have been compiled from C++ sources, so dependencies in that accounting scheme derive from transitive closure.

Alternatively i consider a compiler might only be presented as a binary, with no visibility as to its own source code, so i consider in that case just a Rust program and a binary that compiles it to a native binary linking with binary object files also of unspecified source code languages.

Sorry, we’re in agreement. My reply was meant to reply to the parent claiming there’s a C++ dependency in the tool chain when building everything from source - that’s true for the Linux kernel today since building GCC requires a C++ compiler as well.
I think the assertion is based on the fact that LLVM is written in C++. Doesn’t directly introduce a C++ dependency to the kernel, but it does introduce it to the toolchain.
But rustc is a cross-compiler, you only need a C compiler for one platform and you get a Rust compiler for all platforms. And it's not like LLVM is doing anything that fundamentally prevents it from being written in Rust (see also the Cranelift backend for Rust, written in Rust). I'm still not quite sure what the concrete concern is. Can you elaborate?
Modern GCC is also primarily written in C++, and has had C++ deps since 2013:

https://github.com/gcc-mirror/gcc/blob/master/gcc/input.cc

You will need to generate code for the target which means LLVM/Clang (a C++ project) must support at the very least some amount of codegen for that target.
You can use the cranelift backend, written in Rust, if you prefer. Nothing about LLVM being the best choice by default has to do with the choice of implementation language.
Or more likely for something that needs to be high performance mrustc, but you obviously have to be careful there.
mrustc is written in C++, so I don't see how it's a counter to what the parent is proposing. I also don't know anything about mrustc's performance characteristics, I didn't think performance was a goal, but it's also been a while since I've checked in on it.
Oh right, I don't even know if there's a C compiler that's not written in C++ that can compile the output of mrustc anyway, so there's that.
To focus on the C/C++ comparison. Rust very much leans towards C++ side of things if you go the std library route. It does bake in some abstraction which would not be appropriate for low level systems development such as the Linux Kernel, which is also not what they're going for.

Rust gives you the option of opting out of that `#[no_std]`, which removes some basic tools, such as allocations, panics etc (I haven't used it much, so this may not be fully precise). As such with no_std you do move closer to what you'd consider C development.

That said rust will still have its restrictions, so some of the wild things you can do in C, isn't possible in rust, at least not without really violating the inner workings of it.

But with unsafe you can technically do most things on the level of C, without the overhead, that C++ would provide, via. its abstractions.

I'd expect the Linux Kernel to move in the direction of developing or using their own libraries and data structures, and that becoming its own bespoke part of their use of the rust language. Such that rust only really provides its safety guarantees and ergonomics. Compile times are also quite quick with no_std, as rust only really struggle with compile times, if you have lots of dependencies.

Circling back:

Rust is more like C++ with std library enabled (default) and C with `no_std`

It's basically a part of the larger project to "Rewrite It In Rust" -- to replace C code with Rust code wherever possible. C is dangerous to work with; and with safe Rust (but not with Zig), entire classes of bugs that have dogged the industry for decades simply go away.
> Whereas for myself and most of the C programmers I know, Zig has sort of filled that similar space and seems to take the concerns of C programmers more seriously and the team has an attitude more in line with the C culture than the Rust team does. I could spend hours writing examples of this but it's even apparent in the way the Zig team has handled its relationship with LLVM, where they seem very serious about trying to not accept it as fundamental to their language and eventually even eliminate the dependency on the C++ code...with Rust it doesn't seem like this is even on the minds of most of the users.

Yes, the Rust language needs a complex optimizing compiler to really be viable. In this respect it is more limiting than ANSI/ISO C. For a lot of contexts, this isn't really a problem though? You aren't going to be able to build the Linux kernel without GCC or Clang anyway…

> The way I see it, Rust is still fundamentally designed to work at a higher level of abstraction than C,

Yes

That is the point

Those abstractions are available to the programmer and compile down as tight and efficient as C

gcc is programmed in C++ too. The language of the compiler doesn't matter. What matters is C makes it too easy to make memory errors which Rust protects you from. This is why Linux should migrate to Rust and you can see this migration starting with adding support for Rust based drivers.
I disagree that the language of the compiler doesn't matter. It absolutely matters in some cases, all of which are cases where (ANSI) C is pretty much the only option because of the inherent difficulty of C++ compilers.
This still doesn't explain why the language of the compiler matters. I could write a C compiler in Pony-lang targeting a 30-year-old MCU were I so inclined.

The available compilers targeting your microcontroller certainly matter, though. You certainly still find lots of options that aren't Rust-compatible, but a non-trivial number microcontrollers are ARM or RISC-V based now, and can be targeted by LLVM/Rust.

What target are you compiling to that gcc doesn't support?
Typically if this is the case, won't you be cross compiling for that target anyway?
This was my impression as well. I haven’t spent enough time with Rust to hold a hard stance on it but it definitely seems like it was not designed for “bare-metal” applications. I hadn’t heard of Zig before this but I’m definitely going to look into it now. Got any recommendations for a good intro to zig?
How is that the case? You have bare pointers and the ability to manipulate them, allocation is explicit and can be disabled, you can remove the stdlib entirely, add your own allocator support, etc etc etc.
I'm aware of that, and the point still stands for me that I'm not sure what the point of writing in Rust is if you do all of those things.
This reads like “I’m not sure what’s the point of power tools if every now and then you need to reach for a plain old hammer or screwdriver”.

What’s the point of high-level languages at all if they’re just going to be implemented on top of a CPU that will happily chase raw pointers and divide by zero if you ask it to?

Because everything else can be expressed safely and more concisely than writing it in C or raw asm. And you have to pay virtually zero abstraction costs for the pleasure: see Rust’s comparative performance in language shootouts. Not infrequently Rust even beats C’s performance due to better visibility for optimizations.

And when you do still have to resort to unsafe low-level bit twiddling, you get to keep all the other benefits of having a modern, powerful language.

Do you genuinely think the Linux kernel is just throwing Rust in to attract kids who just follow the latest programming fads?

Well, sorry, but you're not being very clear. First you said it didn't seem designed for low level and now you're saying you aren't sure what the point is if it can do low level things?

It would help if you clarified. I don't want to try to clarify things and end up putting words into your mouth.

The point is that you limit where you're doing that.

Like just as an example - I can write an allocator and toggle register bits etc. All of that requires unsafe code, raw pointers, etc.

But I can then build on top of that in safe Rust, with all the guarantees that brings. I still have to check that the unsafe allocator or whatever work soundly, but Rust checks the stuff on top of it.

This gives a decent overview of some of the areas where the focus of Zig is different than Rust. Other than that...I'd just start by reading through the standard library code and the repo to get a feel. It's very very similar to C so you will be immediately comfortable, just cleans up some stuff like removing default global allocator (you pick your malloc basically), better macros (comptime), and encouraging use of non-null terminated strings and fat pointers etc.

https://ziglang.org/learn/why_zig_rust_d_cpp/

I use Rust for bare-metal development (no libc, no allocator, no panic, 32k size limit), and it is comparable to C and C++ for that use-case. The project is 99.5% Rust with a bit of assembly glue for startup/interrupt handlers.
It is not designed for, but Rust works well on microcontrollers, such as Arduino. For example, a blink program for Arduino in Rust is less than 300 bytes in size when compiled with "s" optimization level. It's a bit larger than C because of vector of interrupt handlers and error handling.
> It is not designed for,

Making sure Rust can work in embedded environments is absolutely a design goal, and choices around this are made explicitly.

>choices around this are made explicitly.

e.g?

A few off the top of my head: the core/std split, making the core language never allocate implicitly, the design of async/await.
> the design of async/await.

I am curious

How is "the design of async/await." for embedded programming?

> Whereas for myself and most of the C programmers I know, Zig has sort of filled that similar space and seems to take the concerns of C programmers more seriously and the team has an attitude more in line with the C culture than the Rust team does.

I agree. In general I think Zig makes lot more sense as a C replacement for the kernel.

However, Rust is stable, and Zig isn't. And I don't expect it will be for some years. So at this point Zig is basically unusable for kernel work.

That doesn't mean it can't be added in the future though, and perhaps even overtake Rust. See: https://news.ycombinator.com/item?id=26815950

>It seems to me that Rust isn't even really intended to compete with C for the use cases in which C is dominant in 2023.

Like?

What other you guys do in C that isn't just integer oriented programming (using ints for everything)?

of course using it as a nice frontend for asm.
> And bare metal or "first compiler" support for bare metal doesn't seem like it's really intended to be a first class use case

Oxide Computer has written an embedded bare-metal OS in Rust, to serve their hardware product: https://hubris.oxide.computer/

I've been writing a little hobby operating system for the past 3 years in Rust and my impression is that the language is fine for low level code. The language improved a lot over the past decade and I think it's ready to be used more.

I've heard good things about Zig but I've never tried it so I can't compare unfortunately.

>The way I see it, Rust is still fundamentally designed to work at a higher level of abstraction than C, and is still mostly dependent on C (even C++ really, due to LLVM/Clang).

I think this might touch on part of the problem. Rust can work on higher abstractions but rust doesn't have to. It is a matter of the code base. I've worked on some that felt very similar in abstraction to C code bases. One in particular was a high performance nginx module. Most of the rust code interfaced with nginx directly through zero cost FFI interfaces to the nginx structs.

I've also worked on extremely meta, high level code that was written by a former Haskell dev.

Like many languages that can serve dual roles, the styles tend to adapt to it. You see very different styles of Java when looking at spring web apps or embedded android systems. Every language you have to pick and chose parts of it that, build a coding standard and need to enforce it. C is exactly the same and also has several roles people pick it for. The style of code of embedded systems, high performance networking systems and codebases that prioritize highly portability tend to be different and use different idioms. I think any of of us who have worked in a C code base that falls in one of those camps can name banned idioms that are normal in the others.

>> It seems to me that Rust isn't even really intended to compete with C for the use cases in which C is dominant in 2023. Every indication is that for "serious Rust in production programming" it's mostly a C++ crowd.

My career before Rust was very C heavy. I've work from OS-less embedded systems, to device drivers, to Android porting. I've been doing Rust professionally since 2016. This just isn't my impression. A lot of folks I've known from college and internships who's careers went a similar direction ended up in rust independently. There is value in having a language that let's us get the job done that we used to do with C but with more high quality static code analysis. The business case and use case is very clear.

While I haven't done any bare metal development in Rust, in the areas I have worked I've found compiler, community and crate support to be great. I don't know where you are getting this impression. I think if I only read hackernews articles about Rust I would get the impressions that is Haskell that can work on bare metal. I've noticed articles that tend to get upvoted here tend to be either about 1) how quick adoption is 2) higher levels of abstraction like HKT or GATs 3) WASM 4) writing web services. This article is a great example of 1. 2 is catnip for this crowd. The majority of rust devs never need to know what a GAT is but if you used HN as a metric you'd think it was a daily problem. 4 is something that is easy to write, makes good content, approachable but isn't necessarily Rust's best use case. I'm not saying you've only been reading this site about Rust, just saying that it is easy to get a skewed impression of the language unless you really dive in.

> If there are any Rust experts around...what am I missing?

Probably more good examples and possibly more ecosystem.

A first big decision is if you're going no-std or not, and if you end up in the no-std world the ecosystem shrinks substantially. If you're building a kernel that's probably not that much of a problem - the same shrinkage occurs for C/C++ - many such projects bootstrap with nearly zero ecosystem anyway.

The examples side is a bigger problem - I've recently been able to watch some of my more curmudgeonly C friends give it a good dive, and after an initial hump they're fairly happy with the core language. They still have regular issues with the ecosystem when they run into, in their words "web dev crap", which comes up even in the stdlib sometimes - a bugbear a while ago coming up down some error handling code paths. They attempted to send patches and hit nebulous arguments against the correctness target, which were largely born of misunderstandings of posix. This kind of thing can come up anywhere, if you take a dependency on some fancy IO abstraction that happens to be written in C, and you take it somewhere "novel" like a BSD, you might well run into the same. The point here is that _examples_ and _exercise_ of these tasks are the things that are going to shake more of this kind of thing out. At the same time though, it's important to reiterate that if you're on the nostd path, then largely you're on your own, which is equivalent to just gcc bare, and this kind of thing generally doesn't come up.

> Or is this a serious proposal about the future of operating systems and other low level infrastructure code?

This is a serious proposal. The outcome is really strong along key axes of correctness and safety. Those of us who've done it (e.g. Fuchsia, where I was) have been able to observe these benefits relative to history with the same teams using other languages (C, C++). We're professional engineers, these statements aren't coming from a place of craziness. The Android team have been writing about their journey: https://security.googleblog.com/search/label/rust

> Do you just program everything in unsafe mode?

Absolutely not. A good amount of bootstrapping effort has been going in across the ecosystem to make it ever easier to avoid unsafe. To take one slice of examples, there's crates that are designed to help you avoid copies while also avoiding dropping to unsafe - they provide tools for automatic structural analysis of the mapping boundary to make it easier to assert the relevant guarantees. Examples: https://docs.rs/zerocopy/latest/zerocopy/ (came out of Fuchsia), https://github.com/serde-rs/serde/releases/tag/v1.0.0 (serde is commonly used, but has more constraints here), https://rkyv.org/rkyv.html (not sure of prominence, but I hear people talk about it).

These kinds of tools get you a long way toward substantially safer code, without needing to think or audit nearly as much. We know that's important, we have plenty of data that demonstrates how important it is, and lately now, we have data that shows how effective it is too (see the aforementioned Android posts).

> What about runtimes?

They're out there, it depends what level of abstraction you're looking for, runtimes means different things to different people. For embedded there's typically a lot more focus on providing libraries rather than a whole runtime framework, so there are crates for a number of soc types out there which are well used, like https://docs.rs/cortex-m/latest/cortex_m/, or it's sibling minimal runtime crate https://docs.rs/cortex-m-rt/latest/cortex_m_rt/. As you get higher level, if you want to do more of the systems level interaction yourself there are a good number of options to choose from along the lines of reactor systems to get you to functional async executors that will build with nostd.

> It seems to me that Rust isn't even really intended to compete with C for the use cases in which C is dominant in 2023. Every indication is that for "serious Rust in production programming" it's mostly a C++ crowd.

The challenge here is that this is an inverted view - it's a C programmers view of C++ being ported over to Rust, and it distorts how the world looks. That doesn't actually apply to the other sides _intent_. Yes, Rust provides a lot more abstraction capabilities than C does, and in that specific regard it has some coarse similarity to C++. It's definitely _possible_ for someone to way off the deep end and produce obscure abstractions around things that a more reductionist bias is going to hate - and you can totally ignore those things and have a great time with the language. There are some really nice things in there which anyone will enjoy if they come at it with an open mind, things like enums and pattern matching, the rich and efficient iterator library, the crates tooling, configuration macros, and so on. There's a lot to love, and they're not things that C++ did well, and comparing it to C++ discards those considerations spuriously.

> Zig has sort of filled that similar space and seems to take the concerns of C programmers more seriously and the team has an attitude more in line with the C culture than the Rust team does

Zig is interesting in it's own right, and on a very surface level it is more similar to C, though this surface level is really "zigs stdlib has terrible and inconsistent short names similar to libc and posix", which isn't really a good measure of anything in particular. It's perfectly functional along this axis and par for the course at the systems programming level.

The toolchain approach has a lot more of a "hacking for hackers" feel, so when you hit bugs and so on it's very typical for folks to be patching their stdlib locally for a while or building their own toolchain to overcome the problems. I spent a little bit of time there recently with building ghostty on windows and was regularly messing with my toolchain and stdlib to make forward progress. Along these lines it's also much less complete - which is largely a function of being much newer, but you can take a ton of rust projects today, particularly things in the GUI space and build them for every major target platform with nearly zero effort. Zig is very very far off that, and there's going to be a need for a lot better platform level abstractions to get there. Rust did a great job with platform abstractions, which sadly was best documented in an anti-go inflammatory articles, but the point stands and if more generalized stands against zig at times too (https://fasterthanli.me/articles/lies-we-tell-ourselves-to-k... and other similar rants he wrote), though not all points port over.

The LLVM removal kind of move is somewhat enabled by this looser approach, which is also helped by the kinds of users the language has, and the smaller ecosystem. Another way of putting that might be "this is the right time to do this", as doing it later might lead to far more user pain and community noise or negativity. It's great for the world as we need more diversity, but it's also not all roses. At my current work we tried out Zig for hermetic cross-builds something that a lot of people tout as a strength. What we found was that the intrinsics that were written in pure Zig were sufficiently far behind libgcc/compiler-rt that it did not have sufficient performance for our use case - literally the binary couldn't handle our production load. Again, this is the kind of thing that can and likely will improve with time, hell if it was a priority I would have done it, but we had other solutions. Point is it's not as simple as a "this vs that" outcome, these moves have long running implications that may or may not affect a particular target - as an example it didn't really harm ghostty at all.

When you talk about culture each of these ecosystems has it's own dominant culture and a wide set of subcultures. How you choose to integrate with those, if you do at all, is up to you. Some might be more attractive for sure, and some might provide a different risk profile for different use cases as well.

Just off the cuff if I was scaling up a team for a professional project with a long lifecycle, I'd probably lean toward rust right now as it has a good balance of stable evolution and production readiness, without being anywhere near as stagnant as C++ despite much effort to move the needle. If I was in a really hacker mood where I just want to twiddle and mess with stuff, I'm not excessively performance sensitive (beyond the general order of magnitude that native compilation and near zero abstractions gets you), and my team is going to remain small and expert "everyone cracks open the source" folks, then I might pick Zig. These days I don't have many good reasons to pick C anymore. If it's patching a pre-existing thing there's no choice of course, but other than that it's mostly going to be "I'm throwing a 30 minute build onto arduino and don't wanna go off the beaten path for this project" kind of thing.

Oh, and if you want to see some real experience writing an OS in Rust, there's someone regularly streaming their experience here: https://www.twitch.tv/sphaerophoria. I've stopped in a few times, they're doing well and the language never impedes them. I gave a couple of pointers in chat with a few points in their initial TCP build, and initial vbe side, again, none of that was language related, more just whoops, a math bug. I just noticed he's streaming and specifically he's porting Doom to his system right now.