> And this is where Rust differs; Rust will reduce the likelihood of bugs from happening in the first place. I'm not saying Zig doesn't also do that, Rust just does it more.
I'd argue that it does this a LOT more. When it comes to spatial safety, Rust and Zig are on par. However in terms of temporal safety I think Zig lags far behind Rust... along with basically every other compiled systems language.
If you had to come up with a single good reason to use Rust over Zig, it would definitely be temporal safety. A majority of applications don't need this though, or can be designed such that they don't.
One of my main issues with Rust is that it makes it easy to write spaghetti code that uses reference counting all over the place. I don't recommend people to use Rust until they become a "N+1 programmer" that Casey Muratori describes as "grouped element thinking" [1]. At this point, most of that programmers problems are solved and suddenly the Zig vs Rust debate becomes much more nuanced.
And those checks are well worth paying for, enough that Rust also has them! I'm sure Rust would have even worse ergonomics if it insisted on no runtime bounds/unwrap checks. The performance cost is low enough that every systems programming language should have spatial safety. To illustrate, Google found that hardening libc++ by adding bounds checks only led to a 0.30% performance impact on their services [1]. It's not hard to imagine that a similar run-time cost affects Zig and Rust. Both languages make attempts to optimize the checks away if the operation is known-safe. Although, maybe Rust is more successful due to the borrow checker.
> and/or misusable allocator passing.
Could you clarify how allocator misuse might lead to a spatial safety violation?
I've done a couple of projects in Rust, and I can appreciate this sentiment.
I don't think my code was pretty and I know it wasn't idiomatic. But I have some experience in writing concurrent code, so I have an understanding of the reasoning behind Rust's borrowing semantics, why lifetimes are important, and the difference between boxed values, rc, arc, and I additionally understand the semantics of semaphores, mutexes, spinlocks, and critical sections.
(As an aside, I don't know if I'm an N+1 programmer. My code works, long term, requires very little maintenance, and generally stays out the way. Just the way I like it.)
But- I see these recurring themes in posts from Rustaceans along the lines of "the compiler tells you what's wrong" and "if it compiles, it's correct!"
These kinds of statements worry me. Not necessarily because I think their code is going to blow something up, but because I think a sizeable portion of the community does not really understand the guarantees Rust provides, and under what contexts they are valid. I mean, sure, you might not have a data race, but you sure as hell can code yourself into race condition or a deadlock, and from what I understand from HNers, these situations are not all that uncommon in Rust crates. I'm also led to believe that the panic handling situation in some crates isn't ideal.
You shouldn't just haphazardly Arc<Mutex<T>> all the things just because that gives you the Send + Sync that you think you're looking for (or the compiler is looking for). You should understand what the hell you're doing, be able to tell if those things are necessary, and understand the ramifications of using those abstractions.
I think there's a lot of good going on in the Rust ecosystem, and I wish I had more work in that area, but there's a lot of blind advocacy there that assumes the Rust approach is the best, but the language does have serious ergonomic limitations in certain low level scenarios. My whole career I've had to focus on scope and objects that outlive their scope, but now every other word I seem to hear from the Rust community is "Lifetimes" and "Ownership", like these concepts were completely unfamiliar to developers before and now the Rust Way(tm) is not only THE WAY, but THE ONLY RIGHT WAY.
I don't want to go too far off the rails, because I find the ecosystem intriguing, and I see tremendous value there. Whether those approaches stand the test of time isn't a given (although let's face it, they probably will because they are sound and they are gaining developer mindshare, which is the most important factor).
I just worry about ergonomics. Coding is not supposed to be easy, so please don't misunderstand- but coding, especially for those that do it day in and day out for decades, should not be a chore. There are definitely some QOL improvements that could be realized in the near term, although I'm not sure what those would look like.
Most of the human-made slop you'll see is going to be, at least on its surface, high quality and well produced since that's what goes viral and gets shared. To that end, I agree with you.
It is worth noting though that the other 99% of human-made slop doesn't make it to you since it never gets popular, hence why hard to filter human-made slop can seem over-represented just through survivorship bias.
I'd argue that it does this a LOT more. When it comes to spatial safety, Rust and Zig are on par. However in terms of temporal safety I think Zig lags far behind Rust... along with basically every other compiled systems language.
If you had to come up with a single good reason to use Rust over Zig, it would definitely be temporal safety. A majority of applications don't need this though, or can be designed such that they don't.
One of my main issues with Rust is that it makes it easy to write spaghetti code that uses reference counting all over the place. I don't recommend people to use Rust until they become a "N+1 programmer" that Casey Muratori describes as "grouped element thinking" [1]. At this point, most of that programmers problems are solved and suddenly the Zig vs Rust debate becomes much more nuanced.
[1] https://www.youtube.com/watch?v=xt1KNDmOYqA