6 ms·
I haven't yet seen a language where full memory safety didn't come at an extraordinary cost [0], and Zig is memory-safe enough to satisfy most programs' demands
by hansvm 2y ago
I haven't yet seen a language where full memory safety didn't come at an extraordinary cost [0], and Zig is memory-safe enough to satisfy most programs' demands [1], especially if you shift your coding model to working with lifetimes and groups of objects rather than creating a new thing whenever you feel like it (which, incidentally, makes your life much easier in Rust and most other languages too).
[0] In Rust, a smattering of those costs include:
- Explicit destruction (under the hood) of every object. It's slow.
- Many memory-safe programs won't type-check (impossible to avoid in any perfectly memory-safe language, but particularly annoying in Rust because even simple and common data structures get caught in the crossfire).
- Rust's "unsafe" is only a partial workaround. "Unsafe" is in some ways more dangerous than C because you don't _just_ have to guarantee memory safety; you have to guarantee every other thing the compiler normally automatically checks in safe mode, else your program has a chance of being optimized to something incorrect.
- Even in safe Rust, you still have a form of subtle data race possible, especially on ARM. The compiler forces a level of synchronization to writes which might overlap with reads, but it doesn't force you to pick the _right_ level, and it doesn't protect you from having to know fiddly details like seq_cst not necessarily meaning anything on some processors when other reads/writes use a different atomic ordering.
- Even in safe Rust, races like deadlocks and livelocks are possible.
- The constraints Rust places on your code tend to push people toward making leaky data structures. In every long-running Rust process I've seen of any complexity (small, biased sample -- take with a grain of salt), there were memory leaks which weren't trivial to root out.
- The language is extraordinarily complicated.
[1] Zig is memory-safe enough:
- "Defer" and "errdefer" cover 99% of use-cases. If you see an init without a corresponding deinit immediately afterward, that's (1) trivially lintable and (2) a sign that something much more interesting is going on (see the next point).
- In the remaining use-cases, the right thing to do is almost always to put everything into a container object with its own lifetime. Getting memory safety correct in those isn't always trivial, but runtime leak/overflow detection in "safe" compilation modes go a long way, and the general pattern of working on a small number of slabs of data (much like how you would write a doubly-linked list in idiomatic Rust) makes it easy to not have to do anything more finicky than remember to deallocate each of those slabs to ensure safety.
- DanielHB 2y agoFrom my point of view the main point of memory safety is not to avoid bugs (although it helps with that) is that when you do have a memory management bug you don't risk remote code executions or leaking sections of memory to attackers (private keys and such).
- aragilar 2y agoThat's assuming a certain type of program is the one you're writing (naturally everyone wants a browser that is bug free and un-exploitable). Not every program talks to the network, not every program handles untrusted data, and not every program has the same risk profile as a browser. Every program has the problem of bugs though, so focusing on making it easy to avoid and fix bugs is more valuable to a wider audience.
- DanielHB 2y agoNot saying that full memory safety is bad, but like the original post said: > I haven't yet seen a language where full memory safety didn't come at an extraordinary cost But like you said yourself there are many types of applications where full memory safety is very important.
- flumpcakes 2y agoI agree with all of your points, and think Zig is perfectly workable. I think for big enterprise software, being written by teams from dozens to hundreds, that Rust probably is a better choice. It would certainly be faster than shipping more electron apps.
- infamouscow 2y agoFor the big enterprise projects, what is the value proposition of Rust compared to the JVM?
- vlovich123 2y agoThere’s a lot to criticize about Rust for sure, but I feel like some of the points here aren’t necessarily in good faith. > Explicit destruction (under the hood) of every object. It's slow. Care to actually support this with data? C++ is quite similar in this respect (Rust has a cleaner implementation of destruction) and generally outperforms any GC language because stack deallocation >> RC >> GC in terms of speed. There’s also a lot of good properties of deterministic destruction vs non deterministic but generally rust’s approach offers best overall latency and throughput in real world code. And of course trivial objects don’t get any destruction due to compiler optimizations (trivially live on the stack). And zig isn’t immune from this afaik - it’s a trade off you have to pick and zig should be closer since it’s also targeting systems programmers. > - Many memory-safe programs won't type-check (impossible to avoid in any perfectly memory-safe language, but particularly annoying in Rust because even simple and common data structures get caught in the crossfire). Actually most memory safe languages don’t have issues expressing data structures (eg Java). And rust has consistently improved its type checker to make more things ergonomic. And finally if you define rust as language + stdlib which is the most common experience those typical data structures are just there for you to use. So more of a theoretical problem than a real one for data structures specifically. > Even in safe Rust, you still have a form of subtle data race possible, especially on ARM. I agree that for the language it’s weird that this is considered “safe”. Of course it’s not any less safe than any other language that exposes atomics so it’s weird to imply this as something uniquely negative to Rust. > Even in safe Rust, races like deadlocks and livelocks are possible. I’m not aware of any language that can defend against this as it’s classically an undecidable problem if I recall correctly. You can layer in your own deadlock and livelock detectors that are however relevant to you but this is not uniquely positive or negative to rust so again weird to raise as a criticism of Rust. > The constraints Rust places on your code tend to push people toward making leaky data structures. In every long-running Rust process I've seen of any complexity (small, biased sample -- take with a grain of salt), there were memory leaks which weren't trivial to root out. I think you’re right to caution to take this with salt. That hasn’t been my experience but of course we might be looking at different classes of code so it might be more idiomatic somewhere. > In the remaining use-cases, the right thing to do is almost always to put everything into a container object with its own lifetime You can of course do that with Rust boxing everything and/or putting it into a container which reduces 99% of all lifetime complexity. There are performance costs of doing that of course so that may be why it’s no considered particularly idiomatic. My overall point is that it feels like you’ve excessively dramatized the costs associated with writing in Rust to justify the argument that memory safety comes with excessive cost. The strongest argument is that certain “natural” ways to write things run into the borrow checker as implemented today (the next gen I believe is coming next year which will accept even more valid code you would encounter in practice although certain data structures of course remain requiring unsafe like doubly linked lists which should be used rarely if ever)