4 ms·
It's not a perfect analogy, but if you want to put yourself in the shoes of the people making it: 1. Rust is an immensely complicated language, and it's not ve
by hansvm 2y ago
It's not a perfect analogy, but if you want to put yourself in the shoes of the people making it:
1. Rust is an immensely complicated language, and it's not very composable (see the async debacle and whatnot). On the simple<->complex slider, it's smack dab on the right of the scale.
2. Ignoring any nitpicking [0], Zig is memory-safe enough in practice, placing it much closer to Rust than to C/C++ on the memory safety axis. My teammates have been using Zig for nearly a year, and the only memory safety bug was (a) caught before prod and (b) not something Rust's features would have prevented [1]. The `defer` and `errdefer` statements are excellent, and much like how you closely audit the use of `unsafe` in Rust there is only a small subset of Zig where you actually need to pull your magnifying glass out to figure out if the code has any major issues. In terms of memory issues I've cared about (not all conforming to Rust's narrow definition of memory safety), I've personally seen many more problems in Rust projects I contribute toward (only the one in Zig, plus a misunderstanding of async as I was learning the language a few years ago, many of varying severity in Rust, at this point probably more code written in Zig than Rust, 10yoe before starting with either).
With that in mind, you have C/C++ on the unsafe axis and Zig/Rust on the safe axis. The complexity axis is self-explanatory, fleshing out the analogy.
Is Zig memory-safe? No, absolutely not. Does that mean that Rust will win out for some domains? Absolutely. In practical terms though, your average senior developer will have many memory safety bugs in C/C++ and few in Zig/Rust. It's a reasonable way to compare and contrast languages.
Is it a perfect description? No, the map is not the territory. It's an analogy that helps a lot of people understand the world around them though.
[0] Even Python is simpler than Rust, and it's memory-safe. If we're limiting ourselves to systems languages, you still have a number of options like Ada and Coq. Rust is popular because it offers a certain tradeoff in the safety/performance/devex Pareto curve, and because it's had a lot of marketing. It's unique in that niche, by definition, but it's far from the only language to offer the features you explicitly stated.
[1] It was just an object pool, and the (aggregate) resetting logic wasn't solid. The objects would have passed through the borrow checker with flying colors though.
Edit: To your GC point, many parts of Rust look closer to GC than not under the hood. You don't have a GC pause, but you have object pools (sometimes falling back to kernel object pools) and a variety of allocation data structures. If RC is a GC tactic, the extra pointer increment/decrement is negligible compared to what Rust actually does to handle its objects (RC is everything Rust does, plus a counter). That's one of my primary performance complaints with the language, that interacting with a churn of small objects is both expensive and the easiest way to code. I can't trust code I see in the wild to behave reasonably by default.
- pcwalton 2y agoI've been seeing C++ fans talk about how they never see memory safety issues in practice in C++ for a decade and a half. I even believed it sometimes. But if there's ever been a common story over those 15 years, it's that these anecdotes mean little, and the actual memory safety property means a lot. The only time I've seen "almost memory safe" actually work is in Go and Swift, which have memory safety problems with concurrency, but they're actually rare enough not to matter too much (though in Go's case it would have been easy to design interfaces and slices not to have the problem, and I wish they had). I simply don't believe that Zig is meaningfully more memory safe than C++.
- fweimer 2y agoI think it's possible to retrofit race-safe slices and interfaces into Go, and I expect it to happen one day once some actually relevant code execution exploit shows up. There's going to be some impact and low-level libraries that manipulate directly the words that constitute slices and interfaces, and there will some slight performance impact and increase in memory usage, but hopefully nothing drastic.
- zozbot234 2y agoI think slices and interfaces in Go are both 2×usize width, in which case you just need double-width CAS to make them safe from data races - which most modern architectures support.
- fweimer 2y agoSlices are base pointer, length, and capacity, so three words. But there's a garbage collector, so you can install a thunk if the slice is updated in a way that torn reads cause problems. It makes reads slightly slower, of course. Two-word loads could be used for interface values (assuming that alignment is increased), except if support older x86-64 is needed. There are implementations that require using CMPXCHG16B, which is a really slow way to load two words. Both Intel and AMD updated their ISA manuals that using VMOVDQA etc. is fine (once the CPU supports AVX and the memory is cacheable).